Поделиться через


Автоматический переключатель отображения

Важный

Некоторые сведения относятся к предварительному продукту, который может быть существенно изменен до его коммерческого выпуска. Корпорация Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых в отношении информации, предоставленной здесь.

В этой статье описывается функция автоматического переключателя отображения (ADS), которая обеспечивает поддержку внутренней панели ноутбука для простого переключения между интегрированным GPU (iGPU) и дискретным GPU (dGPU). ADS — это необязательная функция WDDM, поддерживаемая начиная с Windows 11 версии 24H2 с обновлением 2025.01D (WDDM 3.2).

В этой статье:

  • GPU0 относится к GPU, к которому подключена интегрированная панель.
  • GPU1 ссылается на GPU, на который должна быть переключена панель.

Обзор

Некоторые выпущенные ноутбуки имеют мультиплексорное устройство ,которое позволяет переключить внутреннюю панель между интегрированным GPU (iGPU) и дискретным GPU (dGPU). В настоящее время графический драйвер инициирует и выполняет переключение на этих ноутбуках без участия операционной системы, что приводит к некоторым нежелательным последствиям для пользователя.

ADS позволяет ОС управлять использованием мультиплексорного устройства в системе для переключения между iGPU и dGPU при выводе изображения на внутреннюю панель. Таким образом, ОС может обеспечить лучший пользовательский интерфейс.

Начальная версия ADS поддерживает только переключение внутренней панели между iGPU и dGPU. В будущем эта функция может быть расширена для поддержки мьюксирования внешних соединителей на ноутбуках, а также.

Высокий уровень проектирования

В общем, система должна обеспечивать отображение содержимого внутренней панели без каких-либо мерцаний или сбоев во время выполнения переключения. ОС не ограничивает эту функцию определенным протоколом отображения. В этой статье описывается, как реализовать ADS с помощью eDP, но существуют более отраслевые стандарты, которые можно использовать (например, MIPI или DSI). Дизайн платформы может использовать другой протокол подключения к экрану, если он может достичь того же интерфейса без каких-либо других изменений ОС.

Подразделы в этом разделе определяют аспекты проектирования функции и подробно описывают подход высокого уровня для каждого аспекта.

Управление мультиплексором

Чтобы уменьшить зависимости между драйверами графики iGPU и dGPU, мьюкс предоставляется как отдельное устройство, которое ОС может управлять независимо от графических драйверов. Преимущества этого подхода:

  1. Это снижает сложность графического драйвера, так как драйверу не нужно знать, как управлять каждым различным мультиплексором, которые может использовать OEM.
  2. Это уменьшает или устраняет зависимости между графическими драйверами, что снижает необходимость в обновлениях драйверов и упрощает выбор графических процессоров и мультиплексоров для OEM.
  3. ОС может переключать мьюкс, если графический драйвер недоступен.

Подключение устройства мультиплексора

Так как это решение предназначено для мьюксирования между внутренним iGPU и dGPU, имеет смысл предоставить мьюкс через ACPI.

Функции драйвера мультиплексора

Драйвер мультиплексора должен соответствовать следующим высокоуровневым функциональным требованиям:

  1. Он должен предоставить состояние мьюкса, целевого объекта, который в настоящее время управляет внутренней панелью, и любые ограничения возможностей.
  2. Он должен предоставить способ активации коммутатора и сообщить о состоянии коммутатора.

Дополнительные сведения об устройствеmux ACPI и его методах можно найти в ACPI.

Для выполнения плавного переключения устройство мультиплексора требует следующих условий во время переключения GPU:

  1. Питание панели. В любой момент коммутатор должен получать питание панели от одной из графических процессоров. Это нормально, чтобы оба GPU одновременно предоставляли питание панели.
  2. Сигналы управления с поддержкой яркости от обоих GPU при переключении.
  3. Уровень яркости (широтно-импульсная модуляция) от обоих GPU при переключении.

Мьюкс переключает следующие сведения между двумя графическими процессорами и панелью:

  1. Сигнал управления с поддержкой яркости
  2. Уровень яркости (широтно-импульсная модуляция)
  3. Шина Aux DisplayPort (DP)
  4. Линия обнаружения горячего подключения (HPD)
  5. Строка данных DP

Мьюкс должен иметь возможность переключаться, если панель не активна. По крайней мере, при переключении внутренней панели мультиплексор не должен активировать сигналы HPD на GPU.

Драйвер GPU никогда не должен вызывать методы мультиплексора ACPI.

Автоматический переключатель отображения DDI

Для удовлетворения требований мультиплексора добавляются несколько DDIs. Существует пять различных точек, в которых ОС вызывает DDIs драйвера во время переключения мультиплексора, используя следующие функции. Различные вызовы зависят от этапа коммутатора и того, управляет ли драйвер GPU, который в настоящее время имеет контроль над дисплеем.

DDI описание
DxgkDdiDisplayMuxPreSwitchAway Вызов драйвера, подключенного к экрану. Этот вызов информирует водителя, что система планирует переключить дисплей на другую GPU (с GPU0 на GPU1).
DxgkDdiDisplayMuxPreSwitchAwayGetPrivateData Запрос на сбор закрытых данных коммутатора от драйвера, подключенного к панели (с GPU0).
DxgkDdiDisplayMuxPreSwitchTo Вызов драйвера, который в настоящее время не подключен к экрану. Этот вызов сообщает драйверу, что ОС планирует переключить дисплей на этот GPU (на GPU1).
DxgkDdiDisplayMuxSwitchCanceled Вызов водителя для указания, что последовательность переключения была отменена до её завершения.
DxgkDdiDisplayMuxPostSwitchAway Переключение мультиплексора завершено, и драйвер GPU0 больше не подключен к дисплею.
DxgkDdiDisplayMuxPostSwitchToPhase1 Коммутатор завершён, и драйвер GPU1 теперь подключён к дисплею. Теперь этот драйвер должен выполнять задачи этапа 1.
DxgkDdiDisplayMuxPostSwitchToPhase2 Переключатель мьюкса завершен, и драйвер GPU1 теперь подключен к экрану. Теперь этот драйвер должен выполнять задачи этапа 2.
DxgkDdiDisplayMuxUpdateState Вызывается при запуске адаптера и возвращается в состояние питания D0, чтобы сообщить драйверу о текущем состоянии мультиплексора.

На каждом этапе необходимо выполнить явные действия, необходимые драйверу. Эти действия описаны далее в этой статье.

Для получения полного списка обновлений DDI, связанных с ADS, см. раздел изменений DDI WDDM для автоматического переключения отображения.

Совместное использование данных между GPU0 и GPU1

В некоторых случаях может быть создан более удобный пользовательский интерфейс, когда:

  • GPU0 и GPU1 относятся к одному и тому же IHV.
  • GPU0 может передавать сведения в GPU1 относительно конфигурации дисплея, непрозрачной для ОС.

Большой двоичный объект данных описывается идентификатором GUID, который драйвер GPU1 может быстро определить, понимает ли он большой двоичный объект данных. На высоком уровне ОС вызывает GPU0 для получения GUID и данных BLOB перед переключением и передает их в GPU1 до того, как потребуется HPD в дисплее.

Драйвер GPU1 отвечает за:

  • Проверка того, что он понимает GUID блоба.
  • Проверка каждого элемента данных в большом двоичном объекте, чтобы избежать каких-либо вредных последствий от неправильно сформированных данных в большом двоичном объекте.

Взаимодействие драйверов

Если драйвер WDDM поддерживает ADS, он должен поддерживать ADS независимо от того, на какой системе OEM он работает и какой другой GPU находится в системе.

Последовательность коммутаторов

Хотя технически возможно переключиться с GPU при остановке его драйвера, в настоящее время этот сценарий не поддерживается. Поэтому переключение выполняется только при условии, что для обоих GPU загружены драйверы, поддерживающие DDI переключение.

Следующая последовательность — это высокоуровневое представление всей последовательности коммутаторов, когда панель активна, где GPU0 и GPU1 представляют iGPU и dGPU соответственно. GPU0 в настоящее время подключен к внутренней панели через мультиплексор, и мы хотим переключиться на GPU1, чтобы отображать на панели.

  1. Вызов коммутатора выполняется на уровне API.
  2. ОС собирает атрибуты текущего состояния внутренней панели (HDR, режим, скорость обновления и т. д.) и проверяет временный режим отображения.
  3. ОС отключает любую топологию отображения из-за HPD из любого GPU в системе.
  4. ОС вызывает драйвер GPU1 DxgkDdiDisplayMuxPreSwitchTo, передавая текущий уровень яркости. Драйвер должен сделать следующее, только если крышка открыта:
    • Включите питание на панель.
    • Задайте сигнал с поддержкой яркости.
    • Задайте уровень яркости, переданный ОС.
  5. ОС отключает вызов DxgkDdiQueryConnectionChange на GPU0, чтобы убедиться, что крышка HPD не может быть обработана до тех пор, пока не будет переключен переключатель.
  6. ОС вызывает драйвер GPU0 DxgkDdiDisplayMuxPreSwitchAway DDI. Драйвер должен:
    • Если крышка находится в активном состоянии, активируйте функцию самообновления панели (PSR1) и убедитесь, что она остается включенной до тех пор, пока не последует запрос ОС на её отключение в дальнейшем в последовательности.
    • Добавьте пакет в список изменений подключения DXGK_CONNECTION_CHANGEс установленным значением ConnectionStatus на MonitorStatusDisconnected и значением MonitorConnect.MonitorConnectFlags.DisplayMuxConnectionChange, установленным на 1.
    • GPU0 не может добавлять пакеты изменений подключения для целевого объекта крышки в очередь. Системная ошибка проверяет, происходит ли это.
    • Возвращает размер любого частного BLOB-объекта данных ADS (GUID и данных) в ОС. Если драйвер GPU0 не выполняет этот вызов, он должен удалить все пакеты статуса подключения ADS, помещенные в очередь, прежде чем вернуться.
  7. Если драйвер GPU0 вернул ненулевой размер приватных данных, ОС выделяет этот размер и передает его в обратный вызов dxgkDdiDisplayMuxPreSwitchAwayGetPrivateData для получения приватных данных коммутатора.
  8. ОС вызывает метод ACPI мультиплексора для переключения с GPU0 на GPU1.
  9. ОС позволяет снова вызвать DxgkDdiQueryConnectionChange для GPU0 .
  10. ОС вызывает GPU0 DxgkDdiQueryConnectionChanges, чтобы обработать пакет подключения MonitorStatusDisconnected с DisplayMuxConnectionChange значение 1.
  11. ОС вызывает GPU0 DxgkddiSettimingsfromvidpn, чтобы деактивировать путь к дисплею, от которого происходит переключение. Драйвер GPU0 должен:
    • Отключите питание панели.
    • Отключите сигнал яркости.
    • Остановите отправку уровня яркости в мьюкс.
  12. ОС обрабатывает отъезд дисплея. Он не активирует изменение топологии, чтобы избежать ненужных изменений топологии.
  13. ОС вызывает обратный вызов GPU1 DxgkDdiDisplayMuxPostSwitchToPhase1, передавая любой приватный Blob (блок бинарных данных) ADS, полученный от GPU0. Драйвер должен:
    • Определите, открыта ли крышка или закрыта.
    • Добавьте пакет в список изменений соединения с DXGK_CONNECTION_CHANGE:
      • Установлен бит в MonitorConnect.MonitorConnectFlags.DisplayMuxConnectionChange.
      • ConnectionStatus устанавливается в MonitorStatusConnected, если крышка открыта, или в MonitorStatusDisconnected, если крышка закрыта.
    • Если крышка закрыта, отключите питание и сигнал яркости на панель.
  14. Если ОС еще не вызвала DxgkDdiQueryAdapterInfo с DXGKQAITYPE_INTEGRATED_DISPLAY_DESCRIPTOR2 для внутреннего целевого объекта GPU1, то делает это. В результате этого вызова ОС также вызывает DxgkDdiQueryDeviceDescriptor.
  15. ОС вызывает DxgkDdiQueryConnectionChange GPU1 для обработки события в списке изменения подключений. Этот вызов приводит к вызову DxgkDdiQueryDeviceDescriptor для нового монитора, который был подключен с помощью HPD.
  16. ОС включает изменения топологии отображения из-за HPD.
  17. ОС будет асинхронно обрабатывать пакеты подключения от GPU0 и GPU1, с DisplayMuxConnectionChange, установленным в 1.
  18. Если GPU1 поставил в очередь MonitorStatusConnected:
    • ОС вызывает функции DWM GPU1 для перечисления режимов.
    • DxgkddiSettimingsfromvidpn вызывается на GPU1 для активации пути отображения.
    • DWM обрабатывает и выводит кадр на путь отображения через GPU1.
    • ОС ожидает появления первого кадра.
  19. ОС вызывает обратный вызов GPU1 DxgkDdiDisplayMuxPostSwitchToPhase2, где драйвер должен отключить PSR1 для отображения, если MonitorStatusConnected был поставлен в очередь GPU1; в противном случае не следует ничего делать.
  20. ОС вызывает функцию DxgkDdiDisplayMuxPreSwitchAway для GPU0 с параметрами . Несмотря на то, что от драйвера не ожидается никаких действий, этот вызов полезен для очистки или ведения учета драйверов, связанных с переключением.
  21. ОС собирает атрибуты текущего состояния внутренней панели. Если состояние панели отличается от того, что ранее было сохранено, ОС активирует данные телеметрии.

Эта последовательность коммутаторов одинакова для iGPU->dGPU и dGPU->iGPU. Может возникнуть ситуация, когда необходимо переключить мультиплексор, если панель неактивна. В этом случае эта последовательность не требуется, и ОС может просто вызывать методы ACPI на мьюксе для переключения.

Большая часть ОС не знает, что драйвер находится в режиме PSR. В результате драйверу по-прежнему нужно создать синхронизации Vsync, перевернуть отчет по завершении и т. д., даже если пользователь не видит этих событий.

Процесс восстановления

Если сбой происходит на любом этапе последовательности переключения, выполняется следующая очистка:

  1. ОС вызывает GPU0 DxgkDdiDisplayMuxSwitchCanceled, если GPU0 DxgkDdiDisplayMuxPreSwitchAway был успешно вызван, но егоDxgkDdiDisplayMuxPostSwitchAway не был вызван.
  2. ОС вызывает GPU1 DxgkDdiDisplayMuxSwitchCanceled, если DxgkDdiDisplayMuxPreSwitchTo был успешно вызван, но его DxgkDdiDisplayMuxPostSwitchToPhase2 не был вызван.
  3. Операционная система повторно включает изменения топологии отображения, если они отключены.
  4. Ос повторно включает вызов DxgkDdiQueryConnectionChange на GPU0 при отключении.
  5. ОС опрашивает подключение крышки на GPU, к которому она подключена.
  6. ОС инициирует сброс конфигурации отображения системы (SDC). Драйвер с панелью, подключенной к ней через мьюкс (возвращенный из DxgkDdiDisplayMuxSwitchCanceled) должен убедиться, что PSR отключен.

Необычные события, которые могут произойти во время переключения

  • Пользователь подключает или отключает внешний монитор

    В рамках последовательности переключений мы отключаем обработку событий HPD операционной системой. Таким образом, любой HPD помещается в очередь и обрабатывается вместе с крышкой при одном атомарном действии.

  • Другое приложение вызывает SDC во время переключения

    В процессе переключения вызовы к SDC блокируются и выполняются после завершения переключения.

  • Драйвер отключается при переключении.

    При остановке драйвера вызовы в последовательности переключения завершаются сбоем, и активируется последовательность восстановления. В разделе PnPStop также подробно описано, как он гарантирует, что экран всегда остаётся видимым.

Сценарии закрытия крышки

Драйвер, как правило, может использовать любой из следующих подходов для обнаружения событий открытия и закрытия крышки:

  • Следить за состоянием крышки от DxgkDdiNotifyAcpiEvent(DxgkPowerStateEvent, PO_CB_LID_SWITCH_STATE)
  • Отслеживайте состояние крышки с помощью обратного вызова PoRegisterPowerSettingCallback(GUID_LIDSWITCH_STATE_CHANGE).
  • Другой, зависящий от платформы способ.

Однако в целом для WDDM драйверы должны использовать подход DxgkDdiNotifyAcpiEvent, так как он позволяет синхронизировать состояние Dxgkrnl и состояние драйвера. Учитывая, что в последовательности переключения и iGPU, и dGPU могут быть GPU1, имеет смысл, чтобы все драйверы ADS отслеживали состояние крышки, даже когда крышка переключается на другое устройство.

Когда ОС обрабатывает событие DisplayMuxConnectionChange из GPU0, он считает, что GPU0 больше не владеет состоянием крышки, поэтому GPU0 не может сообщать больше пакетов состояния подключения для этого целевого объекта, пока крышка не переключится обратно. Если GPU0 выполнит это действие, ОС выполнит проверку на ошибки. После того как операционная система обработает DisplayMuxConnectionChange с GPU1, она считает GPU1 владельцем состояния крышки. Любые события открытия или закрытия крышки могут быть проигнорированы между этими двумя событиями, так как ожидается, что GPU1 будет знать состояние крышки и правильно сообщить пакет DisplayMuxConnectionChange.

Когда ОС считает, что драйвер владеет панелью

В следующей таблице описываются последовательные этапы, на которых ОС рассматривает GPU как владеющего панелью. Принадлежащий GPU может сообщать об изменениях в подключении с помощью переключающей последовательности. Номера шагов относятся к ранее описанной последовательности коммутаторов.

Этап из Этап до Какая графическая карта контролирует панель
Перед переключением Шаг 5 GPU0
Шаг 6 Шаг 12 Нет GPU
Шаг 13 После переключения GPU1

Ошибка ОС проверяет, отображается ли пакет изменения соединения в очереди драйвера для мультиплексированного целевого объекта, когда GPU не управляет панелью.

Самостоятельное обновление панели управления (PSR)

Функция ADS использует PSR, чтобы избежать сбоев во время перехода. В частности, PSR1 (режим полноэкранного обновления) используется, чтобы GPU0 и GPU1 не нужно было согласовывать, какой режим PSR использовать.

Даже в PSR1 существуют необязательные функции, которые панель должна поддерживать.

Приемные возможности подробные сведения Устройство, предоставляющее данные через
Версия DPCD & eDP Обеспечение поддержки eDP версии 1.3 или более поздней. DPCD
Возможности и версии PSR Приемник должен поддерживать версию 1. DPCD 00070h bit 7:0
Поддержка VSC SDP для передачи состояния PSR Только для PSR; приемник должен поддерживать по крайней мере версию 2 с до 8 допустимых байт для передачи состояния PSR и значения CRC. DPCD 170
Приемник должен правильно сообщать о состоянии, связанном с PSR Приемник должен предоставлять состояние; например, ошибка CRC соединения, ошибка памяти хранения RFB, состояние самообновления устройства приемника, максимальное число кадров повторной синхронизации, задержка последней фактической синхронизации в приемнике и последняя полученная PSR SDP. DPCD 2008h, 2009h, 200Ah должны отражать правильное состояние приемника.

Когда GPU1 выполняет тренировку связей в рамках вызова DxgkddiSettimingsfromvidpn из ОС, драйвер не знает настройки полосы и пропускной способности DP, используемые GPU0, поэтому должен выполнять полную последовательность тренировки связей, а не быструю тренировку. ОС не будет согласовывать политики PSR между GPU, поэтому необходимо, чтобы панель поддерживала все версии и функции PSR, используемые GPU. Например, панель должна поддерживать сценарий, в котором GPU0 может использовать PSR2 с некоторыми наборами функций, то PSR1 будет использоваться для коммутатора, а GPU1 может использовать PSR2 с другим набором функций.

Обеспечение пребывания панели в PSR во время переключения

Когда GPU1 устанавливает режим на панели, нет никаких гарантий, что заданные GPU1 атрибуты ссылок во время нахождения панели в PSR будут соответствовать режиму включения PSR. Например, скорость обновления или активный размер могут измениться. Сегодня стандарты DP или другие отраслевые стандарты не предусматривают способ, чтобы панель могла сообщить, что она способна удерживать панель в PSR в то время, когда изменяются атрибуты связи. В долгосрочной перспективе мы хотим, чтобы эта возможность была добавлена в спецификацию DP. До тех пор, пока это не произойдет, производитель оригинального оборудования для системы с поддержкой ADS должен выбрать такую комбинацию TCon/panel/Mux, которая способна оставаться в PSR в то время, как атрибуты канала связи (например, частота обновления, активная величина) изменяются между любыми двумя комбинациями, указанными в EDID. Этот подход гарантирует, что PSR может оставаться активным во время переключения.

Для проверки того, что PSR поддерживается в процессе переключения, мы хотели бы, чтобы ОС могла определить, не был ли PSR активен после тестирования режима на GPU1. Сложность заключается в том, что не определено, как панель будет реагировать, если она не сможет поддерживать PSR в процессе установки соединения.

В рамках DxgkDdiDisplayMuxPostSwitchToPhase2драйвер возвращает логическое значение в pWasPanelInPSR, чтобы сообщить ОС, обнаружена ли панель, которая не находилась в PSR.

EDID внутренней панели

Для обеспечения ожидаемого поведения операционной системы при выборе режимов отображения и топологий с разными подключенными мониторами, обе GPU должны сообщать о EDID/DisplayId для внутреннего дисплея. Это требование гарантирует, что база данных CCD, в которой хранятся режимы отображения и топологии, будут выбирать те же параметры независимо от того, какой GPU управляет внутренним дисплеем.

EDID, который драйверы должны передавать ОС, должен быть идентификатором EDID, который запрашивается с панели с помощью команды aux без каких-либо изменений.

В настоящее время ОС вызовет DxgkDdiQueryAdapterInfo(DXGKQAITYPE_INTEGRATED_DISPLAY_DESCRIPTOR2) при запуске драйвера, который сообщает о наличии внутренней панели. Если мьюкс переключается с этого интегрированного целевого объекта, драйвер не может взаимодействовать с панелью для сбора необходимых сведений. Решение заключается в том, что при запуске драйвера и переключении мультиплексора с внутреннего целевого устройства, OS задерживает вызов DxgkDdiQueryAdapterInfo(DXGKQAITYPE_INTEGRATED_DISPLAY_DESCRIPTOR2) до тех пор, пока мультиплексор не переключится на внутреннее целевое устройство.

Как ОС решает, включена ли функция ADS в системе и разрешена ли переключение

Ос выполняет следующие проверки, чтобы определить, доступна ли ADS в системе. Все проверки должны быть верными для поддержки ADS.

  1. Существует GPU, помеченный как интегрированный гибридный (DXGK_DRIVERCAPS.HybridIntegrated), который:
  2. Существует GPU, помеченный как дискретный гибридный (DXGK_DRIVERCAPS. HybridDiscrete), что:
  3. Имена mux ACPI, возвращаемые методом ACPI DMID из шагов 1 и 2, совпадают.
  4. Устройство мультиплексора ACPI имеет методы ACPI DMQU, DMCF и DMSL.
  5. Метод MUX ACPI DMQU вернул имя ACPI внутренней панели целевого объекта с одного из графических процессоров (GPU).
  6. В настоящее время ADS поддерживает только системы с одной внутренней панелью.
  7. Либо
    1. GPU0, GPU1 и Mux ACPI сообщают о полной поддержке ADS.
    2. GPU0, GPU1 и Mux ACPI сообщают либо об экспериментальной, либо о полной поддержке ADS, и установлен ключ реестра EnableMDMExperimentalFeature.

Условия 1 и 2 подразумевают, что оба адаптера должны быть запущены для переключения мьюкса.

Управление качеством развертывания функций ADS

Для обеспечения хорошего пользовательского опыта все следующие компоненты должны работать совершенно.

  1. Функция многомерного отображения ОС.
  2. Методы ACPI платформы для переключения мультиплексора.
  3. Функциональность переключения дисплейных мультиплексоров в драйверах iGPU и dGPU.

Чтобы у IHV/OEM была возможность иметь код качества недоставляемого ПО в выпусках, они могут предоставлять доступ к любому из следующих уровней поддержки ADS:

  • Нет поддержки: драйвер не поддерживает какие-либо функции ADS.
  • Поддержка разработки: драйвер поддерживает ADS, но реализация драйвера по-прежнему находится в процессе разработки и не должна использоваться за пределами этой цели.
  • Экспериментальная поддержка: драйвер поддерживает ADS, но еще не имеет качества, достаточного для выпуска. ОС не включает ADS по умолчанию, но его можно настроить для включения.
  • Полная поддержка: драйвер поддерживает ADS на уровне готовности к производству. ОС считает, что драйвер поддерживает ADS.

Отображение атрибутов, которые должны оставаться неизменными после переключателя отображения

Переключатель отображения не должен изменять какие-либо из следующих атрибутов отображения:

  1. Разрешение рабочего стола
  2. Путь VidPn (включая исходный режим VidPn, целевой режим, масштабирование и т. д.)
  3. DPI (точек на дюйм)
  4. Настройка ночного света
  5. Гамма
  6. Отображение топологии
  7. Включение и отключение HDR
  8. Уровень белого уровня SDR
  9. Профиль цвета
  10. Тип целевого объекта монитора OPM
  11. Яркость дисплея

Сопоставление возможностей GPU для плавного переключения

Чтобы предоставить пользователю бесшовный опыт переключения, дисплей должен быть настроен таким же образом после переключения, как и до переключения. Для реализации этого поведения требуется, чтобы обе видеокарты поддерживали одинаковые функции. Например, если один GPU поддерживает HDR, а другой не поддерживает, то переключение во время включения HDR на одном GPU не будет плавным.

В следующей таблице перечислены функциональные возможности и характеристики графических процессоров, а также описаны требования к выравниванию между двумя ГПУ.

функция GPU, необходимые для обеспечения бесшовной поддержки
HDR Если панель поддерживает HDR, то обе GPU должны либо поддерживать HDR fp16, либо не поддерживать HDR вообще.
Курсор Hw Нет. ОС адаптируется к различным функциям курсора без видимого нарушения работы пользователя.
MPO Нет. ОС адаптируется к различным функциям MPO без видимого нарушения работы пользователя.
PSR Оба GPU должны поддерживать эту функцию.
EDID/DisplayID Оба GPU должны предоставлять один и тот же EDID/DisplayId.
Ограничения яркости Оба GPU должны поддерживать один и тот же интерфейс яркости и ограничения яркости.
Уровни яркости Оба GPU должны предоставлять одинаковые уровни яркости и интервалы.
Резолюция Оба GPU должны поддерживать одинаковые режимы источника и разрешение целевых объектов.
Частоты обновления Дополнительные сведения см. в статье Проблема, если GPU1 не поддерживает частоту обновления, которую GPU0 выполняет панель на.
Динамическая частота обновления Нет. ОС адаптируется к другой поддержке виртуальной частоты обновления.
Переменная частота обновления Дополнительные сведения см. в статье Проблема, если GPU1 не поддерживает частоту обновления, которую GPU0 выполняет панель на.

Проблема, если GPU1 не поддерживает частоту обновления, на которой GPU0 работает с панелью.

Если GPU1 не поддерживает тот же режим, что и GPU0, то сокращенный режим, скорее всего, будет храниться в базе данных топологии отображения. Затем, когда система переключается обратно на GPU0, будет установлен сокращенный режим. Например, если GPU0 поддерживает 120Гц, но GPU1 поддерживает только 60Гц, то может произойти следующая последовательность:

  1. Система настроена таким образом, что GPU0 управляет дисплеем и режим составляет 120Гц.
  2. Пользователь вручную переключается на GPU1.
  3. База данных топологии отображения содержит 120Гц, записанных для дисплея, но GPU1 не поддерживает эту частоту, поэтому ОС выбирает 60Гц.
  4. 60Гц задано и хранится в базе данных топологии отображения.
  5. Пользователь вручную переключается на GPU0.
  6. Топология дисплея считывает частоту 60Hz из базы данных.

Чтобы обеспечить наилучший опыт, производитель должен выбрать iGPU и dGPU, поддерживающие максимальную частоту обновления внутренней панели. Если это невозможно, и один GPU не может поддерживать максимальную частоту обновления панели, gpu, поддерживающий частоту обновления панели, должен поддерживать функцию динамического обновления Windows (DRR) с диапазонами, которые включают:

  • Максимальная частота обновления другого GPU.
  • Самая высокая частота обновления внутренней панели.

Например, если панель может поддерживать 300Гц и iGPU может поддерживать только 60Гц, то dGPU должен поддерживать VRR с диапазоном не менее 60Гц до 300Гц.

Чтобы подвести итог, требование ADS для частоты обновления следующее:

  1. IGPU и dGPU поддерживают максимальную частоту обновления внутренней панели.
  2. GPU, поддерживающий максимальную частоту обновления внутренней панели, должен поддерживать DRR с диапазоном от максимальной частоты обновления, которую может поддерживать другой GPU, до максимальной частоты обновления внутренней панели.

HDR и Dolby Vision

ОС устанавливает то же состояние HDR/Dolby Vision на внутренней панели GPU1 после переключения, как было установлено на внутренней панели GPU0 перед переключением. Пользователь не должен заметить никаких изменений.

Ночной свет

Подсветка экрана реализована через гамма- или цветовую матрицу WDDM DDIs. В обоих случаях ОС устанавливает одинаковые уровни ночного света через GPU1 после переключения, как это было с GPU0 до переключения.

Профиль цвета

ОС применяет тот же цветной профиль к панели после применения переключателя, что и перед переключением.

Отображение экрана проверки ошибок

В настоящее время ОС поддерживает отображение экрана проверки ошибок на устройствах, отличных от POST. При возникновении ошибки операционная система:

  • Не переключает мьюкс.
  • Использует текущую поддержку ОС для отображения экрана проверки ошибок.

При оценке потенциальных целевых объектов для отображения проверки ошибок ОС пропускает все целевые объекты, подключенные к мультиплексору, который переключается на другой целевой объект.

Существует небольшой период времени, когда HPD от GPU0 был обработан, но HPD из GPU1 еще не полностью обработан. Если в течение этого периода происходит проверка ошибок, пользователь не увидит проверку ошибок. Если проверка ошибок возникает в небольшой период времени, когда PSR по-прежнему включен, драйвер, контролируемый дисплеем, должен убедиться, что панель не находится в режиме PSR, когда ОС вызывает DxgkDdiSystemDisplayEnable.

Алгоритм адаптивной яркости содержимого

В идеальном мире адаптивный алгоритм содержимого, используемый обоими GPU, должен производить тот же эффект. Однако тот же эффект, скорее всего, не будет таким, и пользователь может заметить разницу при переключении внутренней панели.

Данные яркости

Чтобы пользователь не заметил изменение яркости из-за переключателя, все атрибуты яркости, предоставляемые GPU0 и GPU1, должны быть идентичными. Это требование гарантирует, что любой уровень яркости до включения GPU0 будет поддерживаться на GPU1 после переключения.

Для этого драйверам GPU0 и GPU1 необходимо:

  1. Используйте тот же интерфейс яркости, DXGK_BRIGHTNESS_INTERFACE_2 или DXGK_BRIGHTNESS_INTERFACE_3, где настоятельно рекомендуется использовать версию 3.
  2. Для интерфейса яркости версии 3 оба драйвера должны предоставлять яркость либо в нитах, либо некалиброванную.
  3. Для интерфейса яркости версии 2 оба драйвера должны возвращать точно одинаковые возможные уровни яркости из GetPossibleBrightness.
  4. Для интерфейса яркости версии 3 оба драйвера должны возвращать одинаковые диапазоны. То есть, каждый драйвер должен возвращать идентичные структуры DXGK_BRIGHTNESS_GET_NIT_RANGES_OUT из GetNitRanges.
  5. Внутренние таблицы, которые драйвер использует для преобразования предоставленных ОС уровней яркости в параметры для определенных панелей, должны совпадать.

В большинстве ноутбуков драйвер GPU получает некоторые или все данные уровня яркости от платформы нестандартно. Мы ожидаем, что для достижения этих требований необходимо расширить обмен данными между платформами и GPU.

Хотя интерфейс яркости запрашивается при запуске адаптера, ОС не будет вызывать DDI интерфейса яркости до тех пор, пока внутренняя панель не будет подключена с помощью HPD. HPD возникает после переключения мультиплексора на GPU, так чтобы драйвер имел доступ к EDID внутренней панели в то время.

Мы понимаем, что для драйвера существуют способы настройки яркости панели для панелей, которые не поддерживают PWM. Однако этот метод усложняет работу TCon, так как он может потребоваться поддерживать получение яркости другим, специфичным для IHV способом, в зависимости от того, какой GPU подключен через мультиплексор.

Конфигурация загрузки мьюкса

Системное встроенное ПО определяет, какое GPU подключено к внутренней панели во время запуска системы. ОС запоминает, какой GPU последним управлял панелью. Затем во время загрузочной последовательности ОС переключает мьюкс при необходимости, чтобы правильный GPU управлял панелью.

Чтобы сохранить любой загрузочный образ, когда требуется мультиплексорный переключатель, этот переключатель выполняется только тогда, когда:

  • Оба графических процессора включены.
  • Операционная система перешла с графики загрузки, которая управляла выводом, на управление выводом с помощью DWM/оболочки.

Таким образом, переключение происходит после вызова DxgkddiSettimingsfromvidpn на GPU, который управляет внутренней панелью, и пользователь будет наблюдать зависание экрана, пока панель находится в PSR во время переключения.

Предоставление сведений об мьюксе драйверу

Эта функция специально разработана так, чтобы операционная система вызывала драйвер для предоставления информации, вместо того чтобы предоставлять обратный вызов, который драйвер может вызывать в любое время. Этот метод позволяет избежать путаницы для драйвера, если он запрашивает состояние ОС во время процесса переключения.

ОС вызывает драйвера DxgkDdiDisplayMuxUpdateState DDI, чтобы предоставить драйверу текущее состояние мультиплексора в следующих случаях:

  1. При запуске драйвера он позволяет избежать ненужного опроса, когда панель не подключена.
  2. При возвращении в D0 из Dx. При возвращении из некоторых состояний питания (например, гибернации) может потребоваться выполнить сброс мультиплексора, поэтому драйвер не знает его состояния.

Эти случаи вместе с обычными DDIs, участвующими в последовательности коммутаторов, гарантируют, что драйвер может определить способ переключения мьюкса в любое время, когда GPU активен.

В первой версии этой функции нет планов переключения мультиплексора, если внутренняя панель не активна, поэтому все переключения будут проходить через одну и ту же последовательность.

Время начала адаптера

При запуске драйвера необходимо реагировать на запросы опроса из ОС. Драйвер может попытаться определить, переключён ли на него мультиплексор, пытаясь установить связь, но это может оказаться времяёмким либо ненадежным. В рамках начальной последовательности GPU ОС вызывает DxgkDdiDisplayMuxUpdateState DDI для каждого целевого объекта, подключенного к муксу, и указывает, переключится ли он на этот целевой объект.

При запуске драйвера необходимо реагировать на запросы опроса из ОС. Драйвер может попытаться выяснить, переключён ли мультиплексор на их GPU, взаимодействуя с ОС, но это может занять много времени или быть ненадежным.

Вместо этого в рамках начальной последовательности GPU ОС вызывает DxgkDdiDisplayMuxUpdateState для каждого целевого объекта, подключенного к муксу, и указывает, переключится ли мьюкс на этот целевой объект. ОС сообщает драйверу, переключен ли мьюкс на GPU драйвера, прежде чем вызывает любые опросные DDI.

Драйвер ADS продолжает сообщать операционной системе об внутренней панели, как и раньше, при вызове ОС DxgkDdiQueryAdapterInfo(DXGKQAITYPE_INTEGRATED_DISPLAY_DESCRIPTOR2) для запроса сведений о внутренней панели. Драйверу необходимо убедиться, что DXGK_CHILD_CAPABILITIES.HpdAwareness установлено в HpdAwarenessInterruptible для любых целевых устройств, подключенных к муксу.

Переход D0

Всякий раз, когда GPU с подключенным модулем возвращается в состояние включения из состояния низкого энергопотребления, ОС вызывает DxgkDdiDisplayMuxUpdateState, чтобы сообщить драйверу, подключен ли мультиплексор к целевому устройству или переключен на другой GPU.

Последовательность загрузки

В следующей последовательности загрузки выделены аспекты, относящиеся к ADS. В этой последовательности системная загрузка выполняется следующим образом:

  • IGPU, подключенный к муксу.
  • Последняя конфигурация пользователя перед перезагрузкой заключалась в том, что мьюкс был подключен к dGPU.

Последовательность загрузки является асинхронной, поэтому эта последовательность предназначена только для примера.

  1. Система включается и iGPU подключается к панели через мьюкс.
  2. IGPU отображает экран загрузки на панели.
  3. Windows загружает и отображает анимацию загрузки на внутренней крышке.
  4. Из-за _DEP как в iGPU, так и в dGPU мультиплексорный драйвер ОС запускается перед любым из драйверов GPU. Драйвер мультиплексора использует вызовы API ACPI, чтобы убедиться, что мультиплексор настроен правильно. Драйвер мультиплексора проверяет, соответствует ли реализация мультиплексора ACPI требованиям ADS.
  5. Dxgkrnl вызывает DxgkDdiAddDevice для iGPU.
  6. Dxgkrnl вызывает DxgkDdiQueryInterface(DXGK_DISPLAYMUX_INTERFACE) для iGPU. Даже если текущая система не поддерживает ADS, драйвер возвращает свой интерфейс, если он поддерживает ADS.
  7. dxgkrnl вызывает DxgkDdiDisplayMuxGetDriverSupportLevel для получения уровня поддержки ADS драйвера.
  8. Dxgkrnl вызывает функцию DxgkDdiDisplayMuxReportPresence(TRUE), чтобы сообщить iGPU, что система имеет в ней функционирующий мультиплексор ADS.
  9. Dxgkrnl вызывает DxgkDdiStartDevice. Драйвер iGPU возвращает количество дочерних объектов, включая целевой объект VidPn для внутренней панели.
  10. Dxgkrnl вызывает DxgkDdiDisplayMuxGetRuntimeStatus, чтобы проверить, поддерживает ли iGPU ADS и получил ли драйвер всю необходимую информацию из системы.
  11. Dxgkrnl вызывает вызовы DxgkDdiQueryChildStatus для каждого дочернего элемента, который предоставляет iGPU.
  12. После того как Dxgkrnl находит дочернее устройство iGPU, подключенное к мультиплексору, он вызывает DxgkDdiDisplayMuxUpdateState, чтобы сообщить iGPU, что мультиплексор подключен к данной цели.
  13. Поскольку iGPU обнаружил подключенный внутренний монитор, Dxgkrnl устанавливает режим на iGPU с помощью DxgkddiSettimingsfromvidpn.
  14. Dxgkrnl запускает драйвер dGPU, а затем повторяет шаги 5-12 для dGPU.
  15. Dxgkrnl обнаруживает, что iGPU, dGPU и мультиплексор настроены правильно, поэтому он создает пару мультиплексоров и свойства интерфейса устройства PnP для этой пары мультиплексоров.
  16. Dxgkrnl считывает последнюю конфигурацию мьюкса из реестра. Так как последняя конфигурация была dGPU, Dxgkrnl теперь запускает последовательность переключения мукса, описанную ранее, для переключения мукса на dGPU.

Драйверы панели

Драйверы панели мониторинга загружаются на основе идентификатора оборудования PnP, созданного из EDID. Учитывая, что EDID остается неизменным, драйвер панели загружается, когда внутренняя панель находится под контролем любой из GPU. Оба драйвера предоставляют одинаковые функции яркости. Таким образом, загрузка не должна стать проблемой, и драйвер панели не должен разбираться, какой GPU управляет мультиплексором.

Идентификация объектов, которые управляются мультиплексором

Когда ОС запускает драйвер, она вызывает функции драйвера DxgkDdiQueryChildRelations, чтобы запросить сведения о сообщаемых дочерних объектах. Драйвер заполняет структуру DXGK_CHILD_DESCRIPTOR для каждого дочернего элемента. Элемент AcpiUid определяется как значение, возвращаемое методом _ADR в этом дочернем пространстве имен ACPI, что позволяет ОС найти имя ACPI для этого дочернего элемента.

Для ADS мы определяем метод ACPI DMID, который должен находиться в дочернем пространстве имен ACPI для целевого объекта. Этот метод DMID возвращает имя ACPI устройства мультиплексора. Она позволяет ОС найти имя мультиплексора ACPI для целевого устройства.

PnP останавливает адаптер, который сканирует на целевой объект

Операционная система не переключает мультиплексор, когда останавливается графический процессор, сканирующий на внутреннюю панель. В следующих сценариях описаны различные случаи остановки GPU.

  1. GPU0 — это пост. Он подключён к внутренней панели и остановлен.

    В этом случае базовый драйвер отображения (BDD) принимает текущий активный режим на GPU0 и продолжает обновлять экран.

  2. GPU0 выполняет инициализацию, а GPU1 подключено к внутренней панели. GPU0 остановлен.

    Из-за текущей архитектуры ОС BDD запускается на GPU0, что приводит к тому, что монитор-призрак определяется и отображается в CPL экрана.

  3. GPU1 не является узлом и подключен к внутренней панели. GPU1 остановлен.

    В связи с текущей структурой ОС BDD не запущен на GPU1, поэтому пользователь не сможет видеть панель.

  4. GPU1 не является постом. GPU0 подключен к внутренней панели, а GPU1 остановлен.

    Нет переключения, и ничего не происходит. GPU0 продолжает отображаться на панели.

Сценарии 2 и 3 создают неприятный опыт для пользователя. Функция ADS изменяет поведение, чтобы устранить эти два случая.

Подключаемые модули и внешние GPU не поддерживаются

Мы не считаем, что для этой функции есть какой-либо вариант использования с подключаемыми GPU.

ADS ограничивается только отдельными внутренними панелями.

Первая версия ADS поддерживает только отдельные внутренние панели. Однако эта функция разработана таким образом, чтобы она поддерживала мультиплексирование внешних и нескольких внутренних дисплеев (при поддержке ОС) в будущем с минимальными изменениями драйверов.

Текущие изменения политики адаптера POST

Операционная система ранее имела некоторые политики относительно адаптера POST. Например, адаптер POST был единственным адаптером, который может предоставлять внутренние целевые объекты. Эти типы ограничений удаляются из ОС с введением ADS.

Отключение визуальных эффектов отслеживания прибытия

При подключении монитора в Windows 11 в оболочке и DWM воспроизводится последовательность анимации. Эта анимация отключена в сценариях переключения дисплея.

Отключение PnP bonk

При добавлении или удалении монитора система PnP воспроизводит звук bonk, чтобы уведомить пользователя. Этот «bonk» отключён в случаях переключения дисплея.

Уведомления о приложении

При возникновении переключателя отображения система проходит через обычные пути к удалению HPD и пути к коду прибытия HPD. Следовательно, все обычные уведомления приложения срабатывают, как и положено; например, уведомления PnP о подключении и отключении HPD и сообщения окна WM_DISPLAYCHANGE.

API для активации коммутатора

План заключается в наличии общедоступного API, чтобы панель управления ОС и IHV могли активировать переключатель.

Учитывая, что внутренняя панель подключена только к одному GPU, интерфейсы API отображения работают должным образом вместе с функциями Win+P.

Тест HLK

Если драйвер GPU или встроенное ПО ACPI сообщает о полной поддержке ADS, необходимо пройти тесты ADS HLK в системе с поддержкой ADS.

Внутренняя панель HPDing GPU при переключении многомерного модуля с этого GPU

ОС запускает проверку ошибок, когда внутренняя панель сообщается как подключенная к драйверу, в то время как данный мультиплексор в настоящее время переключается на другой драйвер.

Переход AC/DC

Для первой версии функции ADS ОС не будет хранить настройки мультиплексора для переменного и постоянного тока и не переключит мультиплексор при переходе с <AC на> DC.

Системные переходы питания

Основная проблема с переходами питания заключается в том, что встроенное ПО сбрасывает состояние мультиплексора (например, при переходе в режим гибернации), а при восстановлении питания мультиплексор не переключается на ту панель, к которой он был подключён до перехода.

Первоначальный подход заключался в том, чтобы переключить мультиплексор обратно на dGPU после включения и iGPU, и dGPU. Проблема с этим подходом заключается в том, что в зависимости от различных асинхронных событий результат может быть несколько изменений в режиме.

Обновленный подход, помогающий оптимизировать пользовательский опыт, заключается в том, чтобы система переключала переключатель обратно на ожидаемый целевой объект, в то время как iGPU и dGPU находятся в режиме сна, тем самым избегая нескольких изменений режима.

Последовательность перехода питания

В следующем примере описывается переход питания в режиме гибернации в системе ADS.

  1. Система сконфигурирована с мультиплексором, подключенным к dGPU.
  2. Система входит в режим гибернации.
  3. IGPU и dGPU переходят на мощность D3.
  4. Система отключается.
  5. Полномочия пользователей в системе.
  6. Встроенное ПО настраивает мьюкс для iGPU и iGPU отображение последовательности загрузки на внутренней панели.
  7. Dxgkrnl считывает последнюю конфигурацию мультиплексора (dGPU в этом случае) и сравнивает её с текущим положением мультиплексора с помощью ACPI (iGPU в данном случае). Dxgkrnl затем вызывает ACPI для переключения мьюкса на dGPU.
  8. Dxgkrnl переходит iGPU в D0, а затем вызываетiGPU DxgkDdiDisplayMuxUpdateState, чтобы сообщить драйверу, что мьюкс не подключен к нему.
  9. Dxgkrnl переводит dGPU в D0, затем вызывает DxgkDdiDisplayMuxUpdateState, чтобы сообщить драйверу, что мультиплексор подключен к нему.
  10. Dxgkrnl задает режим dGPU.

Все системы в одном (AIO)

Любая система AIO, которая хочет поддерживать ADS, должна иметь внутреннюю панель, представленную как внутренний целевой тип для обоих графических процессоров.

Устройство Mux ACPI

Изготовитель оборудования отвечает за добавление устройства мультиплексора в пространство имён ACPI и предоставление необходимых методов для управления мультиплексором.

Драйвер GPU никогда не должен вызывать методы ACPI мьюкса, так как устройство мьюкса может находиться в любом месте дерева ACPI. Рекомендация заключается в том, чтобы найти мьюкс под ближайшим общим предком обоих GPU.

Текущие устройства мультиплексоров поддерживают только два входа, и мы не ожидаем, что будущие мультиплексоры будут поддерживать более двух входов, поэтому проект может предполагать два входа и один выход для каждого мультиплексора.

Устройство мьюкса никогда не может быть остановлено во время работы системы. Это скрытое системное устройство.

Методы ACPI устройства Mux

Только стек драйвера для устройства ACPI может вызывать методы ACPI на данном устройстве. Таким образом, чтобы вызвать методы устройства мультиплексора для переключения мультиплексора, ОС должна загрузить драйвер для устройства мультиплексора. По этой причине ОС теперь предоставляет драйвер мультиплексора дисплея в качестве драйвера для всех мультиплексоров переключателя дисплея.

Для мультиплексора требуется наличие следующих методов:

  • _HID определяет устройство мьюкс по идентификатору оборудования. Мы зарезервировали 'MSFT0005' для мультиплексора дисплея ACPI.
  • DMQU (запрос мультиплексора дисплея) возвращает текущее состояние мультиплексора.
  • DMCF (настройка мультиплексора отображения) настраивает мультиплексор.

Метод _HID (идентификатор оборудования)

Аргументы:

Никакой

возвращает :

Строка ASCII, содержащая идентификатор оборудования, который является "MSFT0005".

Метод DMQU (запрос многомерного отображения)

В будущем выпуске мы ожидаем добавить дополнительные сведения в запрос. Чтобы включить дополнительные запросы в будущем, Arg0 используется для указания типа запроса. Если метод DMQU не понимает тип запроса, он должен завершать выполнение с ошибкой о неподдержке.

Аргументы:

Arg0: целое число, указывающее тип запроса. В следующей таблице перечислены значения типов запросов и их значения.

Значение типа запроса Значение
1 Запрос состояния текущего коммутатора
2 Запрос уровня поддержки mux ADS
3 Запрос первого дочернего элемента GPU, к которому подключена мьюкс
4 Запрос второго дочернего элемента GPU, к которому подключена мьюкс

возвращает :

Если метод понимает указанный тип запроса, он должен возвращать соответствующие данные, как описано в следующей таблице. Если метод не понимает указанный тип запроса, он должен вернуть пустую строку.

Значение типа запроса Возвращаемые данные
1 Строка ASCII, содержащая имя ACPI дочернего устройства GPU, на которое в настоящее время переключается мьюкс.
2 Целое число, представляющее уровень поддержки ADS. Дополнительные сведения см. в следующей таблице.
3 Строка ASCII, содержащая имя ACPI первого дочернего устройства GPU, к которому подключен мультиплексор.
4 Строка ASCII, содержащая имя ACPI второго дочернего устройства GPU, к которому подключен мультиплексор.

В следующей таблице перечислены значения уровня поддержки ADS и их значения, если тип запроса равен 2.

Возвращенные данные Значение
0 Поддержка не поддерживается
1 Поддержка разработки. Системы могут поставляться с этим параметром без прохождения каких-либо тестов HLK, так как ADS по умолчанию будут отключены в клиентских системах.
2 Экспериментальная поддержка. Системы могут поставляться с этим параметром без прохождения каких-либо тестов HLK, так как ADS по умолчанию будут отключены в клиентских системах.
3 Полная поддержка. ADS будет включаться по умолчанию на этой системе, если она оснащена полностью поддерживаемыми графическими драйверами. Системе необходимо пройти тесты ADS HLK для отправки.

Метод DMCF (настройка мьюкса отображения)

Аргументы:

Arg0: ASCII-имя дочернего устройства GPU ACPI, на которое должен переключиться мультиплексор.

возвращает :

Целое число 0 означает успешность; ненулевое значение указывает на сбой. OEM может определить ненулевое значение для улучшения диагностики.

Методы ACPI устройства GPU

Перед запуском графического драйвера для GPU система должна знать, работает ли устройство ACPI (Mux) и каково его текущее состояние. Чтобы сделать это, драйвер устройства мультиплексора ACPI должен быть уже запущен. Система использует метод ACPI _DEP в пространстве имен ACPI каждого GPU для обеспечения связи устройств.

Если gpu уже имеет метод _DEP, он должен добавить имя ACPI устройства мьюкса в возвращенный список зависимостей. Если gpu еще не имеет метода _DEP, он должен добавить его.

Чтобы прошивка ACPI объявляла зависимость GPU от мультиплексора только в том случае, если ОС поддерживает ADS, добавляется запрос ACPI _OSI. Встроенное ПО ACPI может использовать этот запрос для проверки поддержки ADS. Версии ОС, поддерживающие ADS, будут сообщать о поддержке, возвращая значение true в ответ на команду _OSI(“DisplayMux”) ACPI.

Методы ACPI дочернего устройства GPU

Для каждого целевого объекта, подключенного к мьюксу, устройство ACPI дочернего объекта предоставляет метод ACPI, возвращающий имя ACPI устройства, к которому он подключен. Дополнительные сведения см. в статье Определение целей, которые контролирует мультиплексор.

Метод DMID (Display Mux Identifier)

Аргументы:

Никакой

возвращает :

Строка ASCII, содержащая имя ACPI-мультиплексора, с которым соединён этот выход.

Пример

В следующем примере показано, как система с двумя графическими процессорами (GPU0 и GPU1) и мультиплексором настраивается и управляется в рамках системы ACPI.

  • Имя устройства ACPI мультиплексора — 'SB.MUX1'.

  • Для GPU0:

    • Имя ACPI GPU0 — 'SB.PCI0.GFX0'.
    • Он предоставляет целевой объект VidPn 0x40f04, который сообщает значение DXGK_CHILD_DESCRIPTOR. AcpiUid 0x400.
    • Имя дочернего устройства ACPI, соответствующее целевому объекту, подключенном к мьюксу, — SB. PCI0. GFX0. DD1F'.
    • Метод ACPI _ADR в разделе "SB". PCI0. GFX0. DD1F возвращает 0x400. Это возвращаемое значение сообщает ОС, что это устройство ACPI соответствует целевому объекту VidPn 0x40f04.
    • Метод ACPI DMID под 'SB.PCI0.GFX0.DD1F' возвращает 'SB.MUX1'.
  • Для GPU1:

    • Имя ACPI GPU1 — SB.PCI0.PEG0.PEGP.
    • Он предоставляет целевой объект VidPn 0x1103, который сообщает значение DXGK_CHILD_DESCRIPTOR.AcpiUid 0x100.
    • Имя дочернего устройства ACPI, соответствующее целевому объекту, подключенном к мьюксу, — SB. PCI0. PEG0. PEGP. EDP1'.
    • Метод ACPI _ADR в разделе "SB.PCI0.PEG0.PEGP.EDP1" возвращает 0x100. Это возвращаемое значение показывает, как ОС определяет, что данное устройство ACPI соответствует целевой VidPn 0x1103.
    • DMID метода ACPI в разделе "SB.PCI0.PEG0.PEGP.EDP1" возвращает значение "SB.MUX1".
  • ОС знает, что цель GPU0 0x40f04 и цель GPU1 0x1103 подключены к одному и тому же мультиплексору с именем ACPI 'SB.MUX1'.

  • Если GPU1 подключен к панели, ОС может переключить мьюкс на GPU0, вызвав метод DMCF в SB. MUX1, передавая SB. PCI0. GFX0. DD1F'

Следующий код языка компьютера ACPI предназначен для соответствующих частей примера. Псевдокод для логики платформы обрамлен символом <>.


DefinitionBlock
{
    Device (MUX1) // This is _SB_.MUX1
    {
        Name (_HID, "MSFT0007")  // _HID: Hardware ID

        Method (DMQU, 1, Serialized)  // DMQU: Display Mux Query
        {
            Switch (ToInteger(Arg0))
            {
                Case (1)
                {
                    If (<Mux is in error>)
                    {
                        Return ("")
                    }
                    If (<Mux switched to GPU0>)
                    {
                        Return ("_SB_.PCI0.GFX0.DD1F")
                    }
                    Else
                    {
                        Return ("_SB_.PCI0.PEG0.PEGP.EDP1")
                    }
                }
                Case (2) 
                {
                    Return (1)  // Mux only has developmental support
                }
                Case (3)
                {
                    If (<Mux is in error>)
                    {
                        Return ("")
                    }
                    Return ("_SB_.PCI0.GFX0.DD1F")
                }
                Case (4)
                {
                    If (<Mux is in error>)
                    {
                        Return ("")
                    }
                    Return ("_SB_.PCI0.PEG0.PEGP.EDP1")
                }

            }
            // Unknown type
            Return ("")
        }

        Method (DMCF, 1, Serialized)  // DMCF: Display Mux Configure
        {
            If (<Arg0 does not match either of the GPU children this mux is connected to>)
            {
                Return (1) // Failure, use 1 to indicate this particular failure
            }

            // Switch the mux

            If (<Mux switch was successful>)
            {
                Return (0) // Success
            }
            Else
            {
                Return (2) // Failure, use 2 to indicate this particular failure
            }
        }
    }

    Scope (_SB_.PCI0.GFX0) // ACPI Device for GPU0
    {
        Method (_DEP, 0, NotSerialized)  // _DEP: Dependency on Mux device
        {
            If (_OSI(“DisplayMux”))
            {
                Return (Package {"_SB_.MUX1"})
            }
            Else
            {
                Return (Package (0x00){})
            }
        }

        Device (DD1F) // SB.PCI0.GFX0.DD1F which is child of GPU that is connected to the Mux
        {
            Name (_ADR, 0x400)  // _ADR: Matches the AcpiUid driver reports for the target connected to mux
            Method (DMID, 0, NotSerialized)  // DMID: ACPI name of the mux this target is connected to
            {
                Return ("_SB_.MUX1")
            }
        }
    }

    Scope (_SB_.PCI0.PEG0.PEGP) // ACPI Device for GPU1
    {
        Method (_DEP, 0, NotSerialized)  // _DEP: Dependency on Mux device
        {
            If (_OSI(“DisplayMux”))
            {
                Return (Package {"_SB_.MUX1"})
            }
            Else
            {
                Return (Package (0x00){})
            }
        }

        Device (EDP1) // SB.PCI0.PEG0.PEGP.EDP1 which is child of GPU that is connected to the Mux
        {
            Name (_ADR, 0x100)  // _ADR: Matches the AcpiUid driver reports for the target connected to mux
            Method (DMID, 0, NotSerialized)  // DMID: ACPI name of the mux this target is connected to
            {
                Return ("_SB_.MUX1")
            }
        }
    }
}

Изменения API

Функция ADS добавляет следующие функции общедоступного API:

  1. Перечислите устройства мультиплексоров в системе.
  2. Запросить информацию о мультиплексоре, например, о целевых объектах, к которым он подключен, и к какому целевому объекту он в данный момент переключен.
  3. Активируйте мультиплексор.
  4. Как определить, когда мьюкс был переключен.

Перечислить устройства мультиплексора в системе

Приложения могут использовать общие API для подключения и воспроизведения для поиска интерфейсов устройств, представляющих функционирующий мультимикшер дисплея. Компоненты пользовательского режима могут использовать Windows.Devices.Enumeration.DeviceInformation. C# или C++ можно использовать с этими API для перечисления устройств мультиплексоров.

// Display Mux device interface
// {93c33929-3180-46d3-8aab-008c84ad1e6e}
DEFINE_GUID(GUID_DEVINTERFACE_DISPLAYMUX, 0x93c33929, 0x3180, 0x46d3, 0x8a, 0xab, 0x00, 0x8c, 0x84, 0xad, 0x1e, 0x6e);

Интерфейс IDisplayMuxDevice

Интерфейс IDisplayMuxDevice добавляется для представления мультиплексора.

В следующем коде показано, как перечислить устройства многомерного отображения, запрашивать их состояния, переключать активный целевой объект отображения и реагировать на изменения состояния с помощью API среды выполнения Windows.

#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Devices.Enumeration.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Devices.Display.Core.h>

#include <string>
#include <sstream>
#include <iomanip>
#include <windows.h>

namespace winrt
{
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Devices::Enumeration;
using namespace winrt::Windows::Devices::Display;
using namespace winrt::Windows::Devices::Display::Core;
} // namespace winrt

void SwitchDisplayMuxTarget()
{
    // PnP device interface search string for Mux device interface
    std::wstring muxDeviceSelector = L"System.Devices.InterfaceClassGuid:=\"{93c33929-3180-46d3-8aab-008c84ad1e6e}\" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True";

    // Execute the device interface query
    winrt::DeviceInformationCollection deviceInformations = winrt::DeviceInformation::FindAllAsync(muxDeviceSelector, nullptr).get();
    if (deviceInformations.Size() == 0)
    {
        printf("No DisplayMux devices\n");
        return;
    }
    printf("%ld display mux devices found\n\n", deviceInformations.Size());

    // Only one mux in first release but here is generic code for multiple
    for (unsigned int i = 0; i < deviceInformations.Size(); i++)
    {
        printf("Display Mux device %ld :\n", i);

        // Get the device interface so we can query the info
        winrt::DeviceInformation deviceInfo = deviceInformations.GetAt(i);

        // Get the device id
        std::wstring deviceId = deviceInfo.Id().c_str();
        printf("    Device ID string : %S \n", deviceId.c_str());

        // Create the DisplayMuxDevice object
        auto displayMuxDevice = winrt::DisplayMuxDevice::FromIdAsync(deviceId).get();
        if (!displayMuxDevice)
        {
            printf("Failed to create DisplayMuxDevice object");
            continue;
        }

        // Check if DisplayMux is active
        auto displayMuxActive = displayMuxDevice.IsActive();
        printf("    DisplayMux state : %s \n", displayMuxActive ? "Active" : "Inactive");
        if (!displayMuxActive)
        {
            continue;
        }

        // Register for call back when the state of the DisplayMux changes
        UINT changeCount = 0;
        auto token = displayMuxDevice.Changed([&changeCount](auto, auto Args) -> HRESULT {
            changeCount++;
            return S_OK;
        });

        // Find targets connected to the DisplayMux and the current target
        auto targetsList = displayMuxDevice.GetAvailableMuxTargets();
        winrt::DisplayTarget currentTarget = displayMuxDevice.CurrentTarget();

        // Switch the display mux to the other target
        // NOTE SetPreferredTarget() is a sync method so use .get() to wait for the operation to complete
        printf("\n");
        if (currentTarget == targetsList.GetAt(0))
        {
            printf("DisplayMux currently connected to first target\n");
            displayMuxDevice.SetPreferredTarget(targetsList.GetAt(1)).get();
            printf("Calling SetPreferredTarget to switch DisplayMux to second target\n");
        }
        else if (currentTarget == targetsList.GetAt(1))
        {
            printf("DisplayMux currently connected to second target\n");
            displayMuxDevice.SetPreferredTarget(targetsList.GetAt(0)).get();
            printf("Calling SetPreferredTarget to switch DisplayMux to first target\n");
        }
        else
        {
            printf("Could not find current target in target list\n");
        }

        // Now read the current position
        currentTarget = displayMuxDevice.CurrentTarget();
        targetsList = displayMuxDevice.GetAvailableMuxTargets();
        if (currentTarget == targetsList.GetAt(0))
        {
            printf("DisplayMux is now currently connected to first target\n");
        }
        else if (currentTarget == targetsList.GetAt(1))
        {
            printf("DisplayMux is now currently connected to second target\n");
        }
        else
        {
            printf("Could not find current target in target list\n");
        }

        // Now unregister for change callback and display the
        displayMuxDevice.Changed(token);
        printf("DisplayMux state change callback was called %ld times\n\n", changeCount);
    }
}

Изменения в DDI WDDM для автоматического переключения экранов

В этом разделе описываются дополнения и изменения, внесенные в DDI WDDM для поддержки ADS. Эти изменения доступны начиная с Windows 11 версии 24H2 с обновлением 2025.01D (WDDM 3.2).

Запрос интерфейса поддержки KMD ADS

Добавляется структура интерфейса DXGK_DISPLAYMUX_INTERFACE_2. Он содержит вызовы ОС для драйвера, необходимые для поддержки ADS версии 2. В начале запуска драйвера операционная система запрашивает поддерживаемый интерфейс ADS драйвера, с InterfaceType, установленным в GUID_WDDM_INTERFACE_DISPLAYMUX_2.

(DXGK_DISPLAYMUX_INTERFACE содержит вызовы ОС для драйвера, необходимые для поддержки функции ADS версии 1. Эта версия использовалась во время предварительной версии ADS.)

Функции KMD для поддержки ADS

KMD реализует следующие функции для поддержки ADS. Dxgkrnl получает функциональный интерфейс KMD ADS через вызов KMD DxgkddiQueryInterface.

Отчетность о возможностях драйвера в ADS

Драйвер сообщает о своем уровне поддержки ADS, когда ОС вызывает свой DxgkDdiDisplayMuxGetDriverSupportLevel DDI. Если драйвер не реализует интерфейс DXGK_DISPLAYMUX_INTERFACE, ОС считает уровень поддержки DXGK_DISPLAYMUX_SUPPORT_LEVEL_NONE.

Драйвер должен сообщить о своем уровне поддержки ADS независимо от того, в какой системе она работает. Уровень поддержки, сообщаемый драйвером, должен основываться только на драйвере. Драйвер не должен учитывать какие-либо из следующих критериев при составлении отчетов о уровне поддержки ADS:

  1. Система OEM.
  2. Любой другой GPU в системе.
  3. Наличие или отсутствие устройства мультиплексора ACPI.
  4. Наличие или нет записей ACPI в узле ACPI GPU.

Обновление целевых показателей отчетности в момент запуска адаптера

При запуске адаптер сообщает все свои дочерние устройства через DxgkDdiQueryChildRelations DDI. В отчете содержатся все внутренние целевые объекты, подключенные к муксу. Внутренний целевой объект содержит поле DXGK_CHILD_CAPABILITIES.Type.IntegratedDisplayChild.DescriptorLength.

Проблема возникает, если мьюкс переключится на другой GPU при запуске адаптера. В этой ситуации драйвер не может взаимодействовать с внутренней панелью для запроса размера EDID/DisplayId. Таким образом, драйвер, предоставляющий интерфейс GUID_WDDM_INTERFACE_DISPLAYMUX_2, должен задать DXGK_CHILD_CAPABILITIES. Type.IntegratedDisplayChild.DescriptorLength к нулю при запуске адаптера, если мьюкс в настоящее время не переключится на GPU драйвера. В противном случае ОС не сможет запустить адаптер.

ОС обновляет свои внутренние сведения о размере внутреннего дескриптора при первой операции переключателя многомерного коммутатора.

Обновление для изменения подключения

Как упоминалось ранее, существует специфический для ADS способ сообщать о состоянии внутренней панели во время автоматической последовательности переключения дисплея. Чтобы указать, что пакет изменения подключения является частью последовательности коммутаторов ADS, флаг DisplayMuxConnectionChange добавляется в DXGK_CONNECTION_MONITOR_CONNECT_FLAGS. Если задан DisplayMuxConnectionChange, это означает, что MonitorStatusConnected или MonitorStatusDisconnectedстатус подключения связан с автоматическим переключением отображения.

DisplayMuxConnectionChange следует использовать только при переключении ADS и не использовать для других целей. Его следует использовать в следующих случаях применения системы ADS:

  • Пока драйвер обрабатывает DxgkDdiDisplayMuxPreSwitchAway.

    Если внутренняя панель подключена, драйвер должен добавить пакет DXGK_CONNECTION_CHANGE в список изменений подключения с DXGK_CONNECTION_CHANGE.ConnectionStatus, установленным в MonitorStatusDisconnected, и DXGK_CONNECTION_CHANGE.MonitorConnect.MonitorConnectFlags.DisplayMuxConnectionChange, установленным в 1. Эти параметры указывают операционной системе, что драйвер отказался от управления внутренней панелью.

  • Когда драйвер обрабатывает DxgkDdiDisplayMuxPostSwitchToPhase1.

    • Сначала драйвер должен определить, подключена ли внутренняя панель.
    • Если панель подключена, драйвер должен добавить пакет DXGK_CONNECTION_CHANGE в список изменений подключения с DXGK_CONNECTION_CHANGE.ConnectionStatus, установленным в MonitorStatusConnected, и DXGK_CONNECTION_CHANGE.MonitorConnect.MonitorConnectFlags.DisplayMuxConnectionChange, установленным в 1.
    • Если панель не подключена, драйвер должен добавить пакет DXGK_CONNECTION_CHANGE в свой список изменений подключения, с DXGK_CONNECTION_CHANGE.ConnectionStatus установленным в MonitorStatusDisconnected и DXGK_CONNECTION_CHANGE.MonitorConnect.MonitorConnectFlags.DisplayMuxConnectionChange установленным на 1.
  • Пока драйвер обрабатывает DxgkDdiDisplayMuxSwitchCanceled.

  • При поступлении целевого опроса во время переключения, DisplayMuxConnectionChange следует устанавливать только для пакетов изменения подключения, добавляемых из DxgkDdiDisplayMuxPreSwitchAway, DxgkDdiDisplayMuxPostSwitchToPhase1или DxgkDdiDisplayMuxSwitchCanceled.

Обновлено руководство для DxgkDdiSystemDisplayEnable

Когда драйвер ADS DxgkDdiSystemDisplayEnable(/windows-hardware/driver/ddi/dispmprt/nc-dispmprt-dxgkddi_system_display_enable) вызывается DDI, драйвер должен убедиться, что PSR отключен в конце вызова DxgkDdiSystemDisplayEnable DDI.

Руководство изготовителя оборудования

Существует несколько аспектов функции ADS, которые находятся на более низком уровне, чем тот, который контролируется ОС на платформе. Важно убедиться, что изготовители оборудования обеспечивают правильную работу. В следующем списке приведены некоторые ключевые моменты, которые необходимо учитывать изготовителям оборудования.

  • Гибридный интегрированный и гибридный дискретный драйвер должны поддерживать ADS.
  • Мьюкс, выбранный для платформы, может управляться с помощью ACPI.
  • Методы _HID, DMQU и DMCF под устройством мьюкса и дочерними устройствами ACPI GPU для внутренних целевых объектов реализованы и имеют метод DMID ACPI.
  • Устройства ACPI обоих GPU должны иметь _DEP, чтобы обозначить их зависимость от устройства ACPI mux.
  • Интерфейсы яркости, крышки и диапазоны, предоставляемые обоими графическими процессорами, точно совпадают.
  • Как описано в разделе данных яркости, настоятельно рекомендуется использовать интерфейс яркости версии 3 вместо интерфейса яркости версии 2.
  • Если используется драйвер панели мониторинга, код должен быть независимым от GPU; то есть ту же логику можно использовать, когда любой GPU находится под управлением панели.
  • По крайней мере для внутреннего мультиплексора, переключение мультиплексора не должно генерировать событие HPD.
  • Если ИЗГОТОВИТЕЛЬ хотел отключить мьюкс в системе, метод DMQU ACPI должен возвращать значение 0 при вызове с параметром Arg0, равным 2.
  • Мультиплексор должен иметь возможность переключаться между GPU, даже если драйверы находятся в низкопотребляющем режиме. В этом случае PSR не будет использоваться.
  • Когда мьюкс переключается с одного GPU на другой, яркость панели должна поддерживаться без каких-либо сбоев яркости. Это можно сделать несколькими способами, включая следующие способы. Изготовитель оборудования отвечает за обеспечение того, чтобы система поддерживала яркость между коммутаторами.
    • Используйте управление яркостью на основе DisplayPort Aux Nits.
    • Используйте Tcon с восстановлением PWM, чтобы избежать сбоя яркости.
  • Панель и Tcon, которые используются, могут оставаться в режиме автономного обновления (PSR1 для eDP), когда конфигурация соединения до и после переключения отображается через EDID и поддерживается как iGPU, так и dGPU. Это включает в себя, но не ограничивается:
    • Частота обновления
    • Активный размер
    • Количество используемых полос eDP и ширина полосы
    • Настройка DSC eDP
    • Используемая версия eDP VSC SDP
    • Версия и функции PSR, используемые для сценариев без переключения