Control de escenarios eliminados de dispositivos en Direct3D 11
En este tema se explica cómo volver a crear la cadena de interfaz de dispositivo Direct3D y DXGI cuando se quita o reinicializa el adaptador de gráficos.
En DirectX 9, las aplicaciones podrían encontrar una condición de "dispositivo perdido" donde el dispositivo D3D entra en un estado no operativo. Por ejemplo, cuando una aplicación direct3D 9 de pantalla completa pierde el foco, el dispositivo Direct3D se convierte en "perdido"; cualquier intento de dibujar con un dispositivo perdido producirá un error silencioso. Direct3D 11 usa interfaces de dispositivo gráfico virtual, lo que permite que varios programas compartan el mismo dispositivo gráfico físico y eliminen las condiciones en las que las aplicaciones pierden el control del dispositivo Direct3D. Sin embargo, todavía es posible que cambie la disponibilidad del adaptador de gráficos. Por ejemplo:
- El controlador de gráficos se actualiza.
- El sistema cambia de un adaptador de gráficos de ahorro de energía a un adaptador de gráficos de rendimiento.
- El dispositivo gráfico deja de responder y se restablece.
- Un adaptador de gráficos está conectado o quitado físicamente.
Cuando surgen tales circunstancias, DXGI devuelve un código de error que indica que el dispositivo Direct3D debe reinicializarse y se deben volver a crear los recursos del dispositivo. En este tutorial se explica cómo las aplicaciones y juegos de Direct3D 11 pueden detectar y responder a cualquier circunstancia en la que se restablezca, quite o cambie el adaptador de gráficos. Los ejemplos de código se proporcionan a partir de la plantilla Aplicación directX 11 (Windows universal) proporcionada con Microsoft Visual Studio 2015.
Instrucciones
Paso 1:
Incluya una comprobación del error quitado del dispositivo en el bucle de representación. Presente el marco llamando a IDXGISwapChain::P resent (o Present1, etc.). A continuación, compruebe si devolvió DXGI_ERROR_DEVICE_REMOVED o DXGI_ERROR_DEVICE_RESET.
En primer lugar, la plantilla almacena el VALOR HRESULT devuelto por la cadena de intercambio DXGI:
HRESULT hr = m_swapChain->Present(1, 0);
Después de ocuparse del resto del trabajo para presentar el marco, la plantilla comprueba el error eliminado del dispositivo. Si es necesario, llama a un método para controlar la condición quitada del dispositivo:
// 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);
}
Paso 2:
Además, incluya una comprobación del error quitado del dispositivo al responder a los cambios de tamaño de ventana. Este es un buen lugar para comprobar DXGI_ERROR_DEVICE_REMOVED o DXGI_ERROR_DEVICE_RESET por varias razones:
- Cambiar el tamaño de la cadena de intercambio requiere una llamada al adaptador DXGI subyacente, que puede devolver el error eliminado del dispositivo.
- Es posible que la aplicación se haya movido a un monitor que esté conectado a un dispositivo gráfico diferente.
- Cuando se quita o restablece un dispositivo gráfico, la resolución del escritorio suele cambiar, lo que da lugar a un cambio de tamaño de ventana.
La plantilla comprueba el VALOR HRESULT devuelto por 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);
}
Paso 3:
Cada vez que la aplicación recibe el error DXGI_ERROR_DEVICE_REMOVED , debe reinicializar el dispositivo Direct3D y volver a crear los recursos dependientes del dispositivo. Libere las referencias a los recursos del dispositivo gráfico creados con el dispositivo Direct3D anterior; estos recursos ahora no son válidos y todas las referencias a la cadena de intercambio deben liberarse antes de que se pueda crear una nueva.
El método HandleDeviceLost libera la cadena de intercambio y notifica a los componentes de la aplicación que liberen los recursos del dispositivo:
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();
}
A continuación, crea una nueva cadena de intercambio y reinicializa los recursos dependientes del dispositivo controlados por la clase de administración de dispositivos:
// Create the new device and swap chain.
CreateDeviceResources();
m_d2dContext->SetDpi(m_dpi, m_dpi);
CreateWindowSizeDependentResources();
Después de restablecer el dispositivo y la cadena de intercambio, notifica a los componentes de la aplicación que reinicializan los recursos dependientes del dispositivo:
// 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();
}
Cuando se cierra el método HandleDeviceLost, el control vuelve al bucle de representación, que continúa dibujando el siguiente fotograma.
Comentarios
Investigación de la causa de errores eliminados del dispositivo
Repetir problemas con errores eliminados del dispositivo DXGI puede indicar que el código gráfico está creando condiciones no válidas durante una rutina de dibujo. También puede indicar un error de hardware o un error en el controlador gráfico. Para investigar la causa de errores eliminados del dispositivo, llame a ID3D11Device::GetDeviceRemovedReason antes de liberar el dispositivo Direct3D. Este método devuelve uno de los seis posibles códigos de error DXGI que indican el motivo del error eliminado del dispositivo:
- DXGI_ERROR_DEVICE_HUNG: el controlador de gráficos dejó de responder debido a una combinación no válida de comandos gráficos enviados por la aplicación. Si recibe este error repetidamente, es probable que indique que la aplicación ha provocado que el dispositivo se bloquee y deba depurarse.
- DXGI_ERROR_DEVICE_REMOVED: el dispositivo gráfico se ha quitado físicamente, desactivado o se ha producido una actualización del controlador. Esto sucede ocasionalmente y es normal; la aplicación o el juego deben volver a crear los recursos del dispositivo, tal y como se describe en este tema.
- DXGI_ERROR_DEVICE_RESET: error en el dispositivo gráfico debido a un comando con un formato incorrecto. Si recibe este error repetidamente, puede significar que el código envía comandos de dibujo no válidos.
- DXGI_ERROR_DRIVER_INTERNAL_ERROR: el controlador de gráficos encontró un error y restablece el dispositivo.
- DXGI_ERROR_INVALID_CALL: la aplicación proporcionó datos de parámetros no válidos. Si recibe este error incluso una vez, significa que el código provocó la condición de eliminación del dispositivo y se debe depurar.
- S_OK: se devuelve cuando se ha habilitado, deshabilitado o restablecido un dispositivo gráfico sin invalidar el dispositivo gráfico actual. Por ejemplo, este código de error se puede devolver si una aplicación usa la Plataforma de rasterización avanzada de Windows (WARP) y un adaptador de hardware está disponible.
El código siguiente recuperará el código de error DXGI_ERROR_DEVICE_REMOVED e imprimirá en la consola de depuración. Inserte este código al principio del método 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
Para obtener más información, consulte GetDeviceRemovedReason y DXGI_ERROR.
Prueba del control quitado del dispositivo
El símbolo del sistema para desarrolladores de Visual Studio admite una herramienta de línea de comandos "dxcap" para la captura y reproducción de eventos de Direct3D relacionadas con el diagnóstico de gráficos de Visual Studio. Puedes usar la opción de línea de comandos "-forcetdr" mientras la aplicación se ejecuta, lo que forzará un evento de detección y recuperación de tiempo de espera de GPU, lo que desencadenará DXGI_ERROR_DEVICE_REMOVED y te permitirá probar el código de control de errores.
Nota DXCap y sus archivos DLL de soporte técnico se instalan en system32/syswow64 como parte de las Herramientas de gráficos para Windows 10 que ya no se distribuyen a través de Windows SDK. En su lugar, se proporcionan a través de la característica herramientas de gráficos a petición que es un componente de sistema operativo opcional y deben instalarse para habilitar y usar las herramientas de gráficos en Windows 10. Puede encontrar más información sobre cómo instalar las herramientas de gráficos para Windows 10 aquí: https://msdn.microsoft.com/library/mt125501.aspx#InstallGraphicsTools