Обработка удаленных сценариев устройства в Direct3D 11
В этом разделе объясняется, как повторно создать цепочку интерфейсов устройств Direct3D и DXGI при удалении или повторной инициализации графического адаптера.
В DirectX 9 приложения могут столкнуться с состоянием", в котором устройство D3D входит в нерабочее состояние. Например, когда полноэкранное приложение Direct3D 9 теряет фокус, устройство Direct3D становится "потерянным"; любые попытки рисования с потерянным устройством автоматически завершаются ошибкой. Direct3D 11 использует интерфейсы виртуальных графических устройств, что позволяет нескольким программам совместно использовать одно физическое графическое устройство и устранять условия, когда приложения теряют контроль над устройством Direct3D. Однако возможность изменения доступности графического адаптера по-прежнему возможна. Например:
- Драйвер графики обновляется.
- Система изменяется с адаптера графики с сохранением питания на графический адаптер производительности.
- Графическое устройство перестает отвечать и сбрасывается.
- Графический адаптер физически подключен или удален.
При возникновении таких обстоятельств DXGI возвращает код ошибки, указывающий, что устройство Direct3D должно быть повторно инициализировано, а ресурсы устройств должны быть повторно созданы. В этом пошаговом руководстве объясняется, как приложения и игры Direct3D 11 могут обнаруживать и реагировать на любые обстоятельства, в которых графический адаптер сбрасывается, удаляется или изменяется. Примеры кода предоставляются из шаблона приложения DirectX 11 (универсальная версия Windows), предоставленного Microsoft Visual Studio 2015.
Instructions
Шаг 1.
Включите проверку на удаленную ошибку устройства в цикл отрисовки. Представить кадр путем вызова IDXGISwapChain::P resent (или Present1 и т. д.). Затем проверьте, возвращается ли он DXGI_ERROR_DEVICE_REMOVED или DXGI_ERROR_DEVICE_RESET.
Во-первых, шаблон сохраняет HRESULT, возвращаемый цепочкой буферов DXGI:
HRESULT hr = m_swapChain->Present(1, 0);
После ухода за всеми остальными работами для представления кадра шаблон проверяет наличие ошибки, удаленной на устройстве. При необходимости вызывается метод для обработки условия удаления устройства:
// If the device was removed either by a disconnection or a driver upgrade, we
// must recreate all device resources.
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
HandleDeviceLost();
}
else
{
DX::ThrowIfFailed(hr);
}
Шаг 2.
Кроме того, включите проверку на удаленную ошибку устройства при реагировании на изменения размера окна. Это хорошее место для проверки DXGI_ERROR_DEVICE_REMOVED или DXGI_ERROR_DEVICE_RESET по нескольким причинам:
- Для изменения размера цепочки буферов требуется вызов базового адаптера DXGI, который может вернуть ошибку удаления устройства.
- Возможно, приложение переместилось на монитор, подключенный к другому графическому устройству.
- При удалении или сбросе графического устройства разрешение рабочего стола часто изменяется, что приводит к изменению размера окна.
Шаблон проверяет HRESULT, возвращенный ResizeBuffers:
// If the swap chain already exists, resize it.
HRESULT hr = m_swapChain->ResizeBuffers(
2, // Double-buffered swap chain.
static_cast<UINT>(m_d3dRenderTargetSize.Width),
static_cast<UINT>(m_d3dRenderTargetSize.Height),
DXGI_FORMAT_B8G8R8A8_UNORM,
0
);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
// If the device was removed for any reason, a new device and swap chain will need to be created.
HandleDeviceLost();
// Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
// and correctly set up the new device.
return;
}
else
{
DX::ThrowIfFailed(hr);
}
Шаг 3.
В любое время, когда приложение получает ошибку DXGI_ERROR_DEVICE_REMOVED , она должна повторно инициализировать устройство Direct3D и повторно создать все ресурсы, зависящие от устройств. Выпустите все ссылки на ресурсы графического устройства, созданные с помощью предыдущего устройства Direct3D; Эти ресурсы теперь недопустимы, и все ссылки на цепочку буферов должны быть выпущены перед созданием нового.
Метод HandleDeviceLost освобождает цепочку буферов и уведомляет компоненты приложения о выпуске ресурсов устройства:
m_swapChain = nullptr;
if (m_deviceNotify != nullptr)
{
// Notify the renderers that device resources need to be released.
// This ensures all references to the existing swap chain are released so that a new one can be created.
m_deviceNotify->OnDeviceLost();
}
Затем он создает новую цепочку буферов и повторно инициализирует ресурсы, зависящие от устройств, контролируемые классом управления устройствами:
// Create the new device and swap chain.
CreateDeviceResources();
m_d2dContext->SetDpi(m_dpi, m_dpi);
CreateWindowSizeDependentResources();
После повторной установки цепочки устройств и буферов он уведомляет компоненты приложения о повторной инициализации ресурсов, зависимых от устройств:
// Create the new device and swap chain.
CreateDeviceResources();
m_d2dContext->SetDpi(m_dpi, m_dpi);
CreateWindowSizeDependentResources();
if (m_deviceNotify != nullptr)
{
// Notify the renderers that resources can now be created again.
m_deviceNotify->OnDeviceRestored();
}
Когда метод HandleDeviceLost завершает работу, элемент управления возвращается в цикл отрисовки, который продолжает рисование следующего кадра.
Замечания
Изучение причины удаленных ошибок устройства
Повторяющиеся проблемы с удаленными ошибками устройства DXGI могут указывать на то, что графический код создает недопустимые условия во время процедуры рисования. Это также может указывать на сбой оборудования или ошибку в графическом драйвере. Чтобы изучить причину удаленных ошибок устройства, вызовите ID3D11Device::GetDeviceRemovedReason перед выпуском устройства Direct3D. Этот метод возвращает один из шести возможных кодов ошибок DXGI, указывающих причину удаления ошибки устройства:
- DXGI_ERROR_DEVICE_HUNG. Драйвер графики перестал отвечать из-за недопустимого сочетания графических команд, отправленных приложением. Если эта ошибка возникает неоднократно, скорее всего, это означает, что ваше приложение зависло и должно быть отлажено.
- DXGI_ERROR_DEVICE_REMOVED: графическое устройство было физически удалено, отключено или произошло обновление драйвера. Это происходит иногда и нормально; Приложение или игра должны повторно создавать ресурсы устройств, как описано в этом разделе.
- DXGI_ERROR_DEVICE_RESET. Сбой графического устройства из-за неправильно сформированной команды. Если эта ошибка возникает неоднократно, это может означать, что код отправляет недопустимые команды рисования.
- DXGI_ERROR_DRIVER_INTERNAL_ERROR. Драйвер графики столкнулся с ошибкой и сбросил устройство.
- DXGI_ERROR_INVALID_CALL. Приложение предоставило недопустимые данные параметров. Если эта ошибка возникает даже один раз, это означает, что код вызвал состояние удаления устройства и должен быть отлаживаем.
- S_OK. Возвращается при включении, отключении или сбросе графического устройства без недопустимого текущего графического устройства. Например, этот код ошибки можно вернуть, если приложение использует платформу расширенной растеризации Windows (WARP), а аппаратный адаптер становится доступным.
Следующий код извлекает код ошибки DXGI_ERROR_DEVICE_REMOVED и выводит его в консоль отладки. Вставьте этот код в начало метода HandleDeviceLost:
HRESULT reason = m_d3dDevice->GetDeviceRemovedReason();
#if defined(_DEBUG)
wchar_t outString[100];
size_t size = 100;
swprintf_s(outString, size, L"Device removed! DXGI_ERROR code: 0x%X\n", reason);
OutputDebugStringW(outString);
#endif
Дополнительные сведения см. в разделе GetDeviceRemovedReason и DXGI_ERROR.
Тестирование удаленной обработки устройства
Командная строка разработчика Visual Studio поддерживает средство командной строки dxcap для записи и воспроизведения событий Direct3D, связанного с диагностикой графики Visual Studio. Вы можете использовать параметр командной строки "-forcetdr" во время работы вашего приложения, которое принудительно приведет к обнаружению и восстановлению gpu, тем самым активируя DXGI_ERROR_DEVICE_REMOVED и позволяя протестировать код обработки ошибок.
Примечание DXCap и библиотеки DLL поддержки устанавливаются в system32/syswow64 в составе средств графики для Windows 10, которые больше не распределяются через пакет SDK для Windows. Вместо этого они предоставляются с помощью компонента "Графические инструменты по запросу", который является необязательным компонентом ОС и должен быть установлен для включения и использования графических инструментов в Windows 10. Дополнительные сведения о том, как установить графические инструменты для Windows 10, см. здесь: https://msdn.microsoft.com/library/mt125501.aspx#InstallGraphicsTools