TDR в Windows 8 и более поздних версиях
Начиная с Windows 8, поведение обнаружения и восстановления времени ожидания GPU позволяет сбрасывать части отдельных физических адаптеров, а не требовать сброса на уровне адаптера.
Дополнительные сведения см. в разделе "Обнаружение времени ожидания" и "Восстановление" (TDR).
Требования
- Минимальная версия WDDM: 1.2
- Минимальная версия Windows: 8
- Реализация драйвера — только полная графика и отрисовка: обязательный
- Требования и тесты WHLK : Device.Graphics... TDRResiliency
Интерфейс драйвера устройств TDR (DDI)
Чтобы обеспечить это изменение поведения, драйверы мини-порта в режиме ядра (KMD) могут реализовать следующие функции:
KMD указывает на поддержку этих функций, задав DXGK_DRIVERCAPS.Элемент SupportPerEngineTDR , в этом случае он должен реализовать все перечисленные функции.
Драйвер, поддерживающий эти функции, также должен поддерживать нулевую синхронизацию для функции DxgkDdiCollectDbgInfo. Это требование гарантирует, что вызовы нулевых KMD могут продолжаться, если операция сброса не влияет на них. См. примечания dxgkDdiCollectDbgInfo.
Следующие структуры связаны с приведенными выше функциями:
- DXGK_DRIVERCAPS
- DXGK_ENGINESTATUS
- DXGKARG_QUERYDEPENDENTENGINEGROUP
- DXGKARG_QUERYENGINESTATUS
- DXGKARG_RESETENGINE
Узлы
Как и в перечисленных функциях TDR, узел является одной из нескольких частей одного физического адаптера, который можно запланировать независимо. Например, 3-D узел, декодирование видео и узел копирования могут существовать в одном физическом адаптере, и каждый из них может быть назначен отдельным порядком узла. Это назначение хранится в DXGKARG_QUERYDEPENDENTENGINEGROUP.УзелOrdinal в вызове DxgkDdiQueryDependentEngineGroup.
Количество узлов в физическом адаптере сообщается драйвером мини-порта отображения в элементе NbAsymetricProcessingNodes DXGK_DRIVERCAPS.GpuEngineTopology.
Порядковое значение узла передается в элементе NodeOrdinal структуры DXGKARG_CREATECONTEXT при создании контекста.
Подсистемы
Как и в функциях DDI TDR, подсистема является одним из нескольких физических адаптеров (или GPU), которые вместе действуют в качестве одного логического адаптера. Dxgkrnl поддерживает такие конфигурации, но требует, чтобы каждый модуль должен иметь одинаковое количество узлов.
Например, планировщик GPU рассматривает подсистему 0 для соответствия физическому адаптеру 0. Подсистема 0 должна иметь то же количество узлов, что и подсистема 1, которая соответствует адаптеру 1.
Порядковое значение ядра при создании контекста
При создании контекста в элементе EngineAffinity структуры DXGKARG_CREATECONTEXT задается один бит, соответствующий порядковой номеру ядра. Элемент EngineOrdinal этой и других структур, связанных с планировщиком, является отсчитываемый от нуля индекс. Значение EngineAffinity равно 1<< EngineOrdinal, а EngineOrdinal — самая высокая битовая позиция в EngineAffinity.
Пакеты, не затронутые сбросом ядра
Планировщик GPU может попросить драйвера повторно отправить пакеты, которые были отправлены слишком поздно в очередь оборудования ядра, чтобы быть полностью обработаны до завершения сброса двигателя. Драйвер должен следовать этим рекомендациям, чтобы повторно отправить такие пакеты:
- Разбиение пакетов на разбиение по страницам: планировщик GPU запрашивает у драйвера повторную отправку разбиения пакетов с исходными идентификаторами ограждения и в том же порядке, что и первоначально отправленные. Все такие пакеты повторно отправляются до добавления новых пакетов в очередь оборудования.
- Отрисовка пакетов: планировщик GPU назначает пакеты отрисовки новых идентификаторов ограждения, а затем повторно отправляет их.
Последовательность вызовов для сброса подсистемы
При успешном выполнении DxgkDdiResetEngine планировщик GPU гарантирует, что значение LastAbortedFenceFenceId, возвращаемое из вызова сброса двигателя, соответствует:
- Существующий идентификатор ограждения в очереди оборудования.
- Последний завершенный идентификатор ограждения на GPU. Эта ситуация может произойти, когда оборудование очищается после обнаружения времени ожидания GPU, но до вызова обратного вызова сброса двигателя.
Драйвер всегда должен поддерживать последнее завершенное значение идентификатора ограждения на GPU, так как этот идентификатор ограждения необходим для задания члена DmaPreempted.LastCompletedFenceId DXGKARGCB_NOTIFY_INTERRUPT_DATA структуры уведомления о прерывании прерывания. Последний завершенный идентификатор ограждения должен быть расширен только в следующих ситуациях:
- После завершения пакета (не предупрежденный), последний завершенный идентификатор ограждения должен быть установлен на идентификатор ограждения завершенного пакета.
- Когда DxgkDdiResetEngine завершается успешно, для последнего завершенного идентификатора ограждения необходимо задать значение члена LastCompletedFenceId , возвращаемого вызовом сброса двигателя.
- Для сброса на уровне адаптера последний завершенный идентификатор забора на всех узлах должен быть расширен до последнего отправленного идентификатора забора во время сброса.
Ниже приведена хронологическая последовательность успешного сброса двигателя, как показано планировщиком GPU:
Выдается попытка вытеснения.
Обнаружено время ожидания GPU.
Планировщик GPU принимает моментальный снимок последних отправленных и завершенных идентификаторов ограждения, а прерывания с подсистемы ожидания игнорируются. Это сочетание является одной атомарной операцией на уровне прерывания устройства.
Если в этой точке в очереди оборудования нет пакетов, закройте его. Эта ситуация может произойти, когда пакет был завершен в период времени между шагами 2 и 3.
Все очередные ЦП удаляются.
Подготовка к сбросу двигателя.
Вызов DxgkDdiResetEngine.
Если элемент LastAbortedFenceId меньше последнего завершенного идентификатора ограждения или больше последнего отправленного идентификатора ограждения, Dxgkrnl вызывает проверку системной ошибки. В файле аварийного дампа ошибка отмечается сообщением BugCheck 0x119, которое имеет следующие четыре параметра:
- 0xA, что означает, что водитель сообщил о недопустимом прерванном идентификаторе ограждения
- Значение LastAbortedFenceId , возвращаемое драйвером
- Последний завершенный идентификатор ограждения
- Параметр внутренней операционной системы
Если допустимое значение LastAbortedFenceId, выполните восстановление сброса двигателя следующим образом. Если сброс двигателя повлиял на пакет разбиения по страницам, планировщик GPU следует сбросу ядра с помощью сброса на уровне адаптера. Все устройства, на которые ссылается этот пакет разбиения на страницы, также помещаются в состояние ошибки. Само системное устройство не помещается в состояние ошибки и возобновляет выполнение после завершения сброса.
Особые случаи
Особая ситуация может возникать, когда пакет завершается на GPU между шагами 3 и 7. В этом случае драйвер должен задать LastAbortedFenceId идентификатору забора последнего завершенного пакета, если в очереди оборудования нет пакетов с точки зрения драйвера. С точки зрения планировщика появляется, что такой пакет был прерван. Поэтому планировщик помещает соответствующее устройство в состояние ошибки, даже если пакет в конечном итоге завершен.
Если драйвер не может выполнить операцию сброса по каким-либо из следующих причин, он должен вернуть код состояния сбоя:
- Оборудование находится в недопустимом состоянии.
- Оборудование не может сбрасывать узлы.
Если планировщик GPU получает код состояния сбоя, он выполняет операцию сброса и перезапуска на уровне адаптера после поведения TDR до Windows 8.
Даже если драйвер выбирает поведение Windows 8 и более поздних TDR, существуют случаи, когда планировщик GPU запрашивает сброс и перезапуск всего логического адаптера. Поэтому драйвер должен по-прежнему реализовывать функции DxgkDdiResetFromTimeout и DxgkDdiRestartFromTimeout, а их семантика остается той же, что и до Windows 8. При попытке сброса физического адаптера с dxgkDdiResetEngine приводит к сбросу логического адаптера, команда !analyze отладчика Windows показывает, что для контекста восстановления TDR задано новое значение TdrEngineTimeoutPromotedToAdapterReset = 9.