Controlar escenarios cuando se quitan dispositivos en Direct3D 11Handle device removed scenarios in Direct3D 11

En este tema se explica cómo recrear la cadena de la interfaz de dispositivo de Direct3D y DXGI cuando se quita o reinicializa la tarjeta gráfica.This topic explains how to recreate the Direct3D and DXGI device interface chain when the graphics adapter is removed or reinitialized.

En DirectX9, las aplicaciones podrían encontrarse con la condición "dispositivo perdido" por la cual el dispositivo D3D adquiere un estado no operativo.In DirectX 9, applications could encounter a "device lost" condition where the D3D device enters a non-operational state. Por ejemplo, cuando una aplicación de Direct3D 9 con pantalla completa pierde el foco, el dispositivo Direct3D pasa a tener la condición de "perdido"; todo intento de dibujar con un dispositivo perdido dará error en forma silenciosa.For example, when a full-screen Direct3D 9 application loses focus, the Direct3D device becomes "lost;" any attempts to draw with a lost device will silently fail. Direct3D 11 usa interfaces de dispositivo gráfico, permitiendo que varios programas compartan el mismo dispositivo gráfico físico y eliminando las condiciones donde las aplicaciones pierden el control del dispositivo de Direct3D.Direct3D 11 uses virtual graphics device interfaces, enabling multiple programs to share the same physical graphics device and eliminating conditions where apps lose control of the Direct3D device. Sin embargo, aún es posible que la disponibilidad de la tarjeta gráfica cambie.However, it is still possible for graphics adapter availability to change. Por ejemplo:For example:

  • El controlador de gráficos se actualiza.The graphics driver is upgraded.
  • El sistema cambia de una tarjeta gráfica de ahorro de energía a una tarjeta gráfica de rendimiento.The system changes from a power-saving graphics adapter to a performance graphics adapter.
  • El dispositivo gráfico deja de responder y se restablece.The graphics device stops responding and is reset.
  • Se conecta o se quita una tarjeta gráfica físicamente.A graphics adapter is physically attached or removed.

Cuando se dan estas circunstancias, DXGI devuelve un código de error que indica que el dispositivo de Direct3D debe reinicializarse y que los recursos de dispositivo deben recrearse.When such circumstances arise, DXGI returns an error code indicating that the Direct3D device must be reinitialized and device resources must be recreated. Este tutorial explica de qué manera las aplicaciones y juegos de Direct3D 11 pueden detectar cualquier circunstancia y responder ante esta cuando se restablece, quita o cambia la tarjeta gráfica.This walkthrough explains how Direct3D 11 apps and games can detect and respond to any circumstance where the graphics adapter is reset, removed, or changed. Los ejemplos de código proceden de la plantilla Aplicación DirectX 11 (Windows universal) que se incluye con Microsoft Visual Studio 2015.Code examples are provided from the DirectX 11 App (Universal Windows) template provided with Microsoft Visual Studio 2015.

InstructionsInstructions

Paso 1:Step 1:

Agrega una comprobación para el error de dispositivo quitado en el bucle de representación.Include a check for the device removed error in the rendering loop. Presenta el marco con una llamada a IDXGISwapChain::Present (o Present1, etc.).Present the frame by calling IDXGISwapChain::Present (or Present1, and so on). A continuación, compruebe si devolvió un dispositivo de error de dxgi _ _ _ quitado o el restablecimiento del **dispositivo de error de dxgi _ _ _ **.Then, check whether it returned DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET.

Primero, la plantilla almacena el valor HRESULT que devuelve la cadena de intercambio de DXGI:First, the template stores the HRESULT returned by the DXGI swap chain:

HRESULT hr = m_swapChain->Present(1, 0);

Después de encargarse de todo el trabajo relacionado con la presentación del marco, la plantilla comprueba si hay error de dispositivo quitado.After taking care of all other work for presenting the frame, the template checks for the device removed error. Si es necesario, llama a un método para controlar la condición de dispositivo quitado:If necessary, it calls a method to handle the device removed condition:

// 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:Step 2:

Además, incluye una comprobación para el error de dispositivo quitado cuando responde a cambios en el tamaño de la ventana.Also, include a check for the device removed error when responding to window size changes. Este es un buen lugar para comprobar si se ha ** _ _ _ quitado el dispositivo de errores de dxgi** o el ** _ dispositivo de errores _ _ de dxgi** por varias razones:This is a good place to check for DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET for several reasons:

  • Cuando se cambia el tamaño de la cadena de intercambio, es necesaria una llamada al adaptador DXGI subyacente, que puede devolver un error de dispositivo quitado.Resizing the swap chain requires a call to the underlying DXGI adapter, which can return the device removed error.
  • La aplicación podría haberse movido a un monitor conectado a un dispositivo gráfico diferente.The app might have moved to a monitor that's attached to a different graphics device.
  • Cuando un dispositivo gráfico se quita o se restablece, la resolución del escritorio suele cambiar y, por lo tanto, cambia el tamaño de la ventana.When a graphics device is removed or reset, the desktop resolution often changes, resulting in a window size change.

La plantilla comprueba el valor HRESULT que devuelve ResizeBuffers:The template checks the HRESULT returned by 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:Step 3:

Cada vez que la aplicación recibe el error de dispositivo de error de DXGI, debe reinicializar el dispositivo Direct3D y volver a crear los recursos dependientes del dispositivo. ** _ _ _ **Any time your app receives the DXGI_ERROR_DEVICE_REMOVED error, it must reinitialize the Direct3D device and recreate any device-dependent resources. Libera todas las referencias a los recursos de dispositivos gráficos que se crearan con el dispositivo anterior de Direct3D (esos recursos ya no tienen validez) y libera todas las referencias a la cadena de intercambio para poder crear una nueva.Release any references to graphics device resources created with the previous Direct3D device; those resources are now invalid, and all references to the swap chain must be released before a new one can be created.

El método HandleDeviceLost libera la cadena de intercambio y notifica a los componentes de la aplicación que liberen recursos de dispositivo:The HandleDeviceLost method releases the swap chain and notifies app components to release device resources:

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();
}

Luego crea una nueva cadena de intercambio y reinicializa los recursos dependientes de dispositivo controlados por la clase de administración de dispositivos:Then, it creates a new swap chain and reinitializes the device-dependent resources controlled by the device management class:

// Create the new device and swap chain.
CreateDeviceResources();
m_d2dContext->SetDpi(m_dpi, m_dpi);
CreateWindowSizeDependentResources();

Una vez que el dispositivo y la cadena de intercambio se hayan restablecido, notifica a los componentes de la aplicación que reinicialicen recursos dependientes de dispositivo:After the device and swap chain have been re-established, it notifies app components to reinitialize device-dependent resources:

// 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 el método HandleDeviceLost finaliza, el control vuelve al bucle de representación, que continúa dibujando el marco siguiente.When the HandleDeviceLost method exits, control returns to the rendering loop, which continues on to draw the next frame.

ObservacionesRemarks

Investigar la causa de los errores de dispositivo quitadoInvestigating the cause of device removed errors

Los problemas repetitivos con errores de dispositivo quitado de DXGI pueden indicar que el código de gráficos está creando condiciones no válidas durante una rutina de dibujo.Repeat issues with DXGI device removed errors can indicate that your graphics code is creating invalid conditions during a drawing routine. También puede indicar un error de hardware o un error en el controlador de gráficos.It can also indicate a hardware failure or a bug in the graphics driver. Para investigar la causa de los errores de dispositivo quitado, llama a ID3D11Device::GetDeviceRemovedReason antes de liberar el dispositivo de Direct3D.To investigate the cause of device removed errors, call ID3D11Device::GetDeviceRemovedReason before releasing the Direct3D device. Este método devuelve uno de seis códigos de error de DXGI posibles, indicando la razón del error de dispositivo quitado:This method returns one of six possible DXGI error codes indicating the reason for the device removed error:

  • DXGI _ ERROR de _ dispositivo _ bloqueado: el controlador de gráficos dejó de responder debido a una combinación no válida de comandos de gráficos enviados por la aplicación.DXGI_ERROR_DEVICE_HUNG: The graphics driver stopped responding because of an invalid combination of graphics commands sent by the app. Si obtienes este error en repetidas ocasiones, puede indicar que la aplicación provocó que el dispositivo dejase de responder y necesita depurarse.If you get this error repeatedly, it is a likely indication that your app caused the device to hang and needs to be debugged.
  • DXGI _ Dispositivo de ERROR _ _ quitado: el dispositivo de gráficos se ha quitado físicamente, está apagado o se ha realizado una actualización del controlador.DXGI_ERROR_DEVICE_REMOVED: The graphics device has been physically removed, turned off, or a driver upgrade has occurred. Esto sucede de manera ocasional y es normal; la aplicación o el juego debe recrear recursos de dispositivo como se describe en este tema.This happens occasionally and is normal; your app or game should recreate device resources as described in this topic.
  • DXGI _ ERROR _ de _ restablecimiento del dispositivo: error en el dispositivo de gráficos debido a un comando con formato incorrecto.DXGI_ERROR_DEVICE_RESET: The graphics device failed because of a badly formed command. Si obtienes este error en repetidas ocasiones, puede significar que el código está enviando comandos de dibujo no válidos.If you get this error repeatedly, it may mean that your code is sending invalid drawing commands.
  • DXGI _ Error _ _ interno del _ controlador de errores: el controlador de gráficos ha detectado un error y ha restablecido el dispositivo.DXGI_ERROR_DRIVER_INTERNAL_ERROR: The graphics driver encountered an error and reset the device.
  • DXGI _ ERROR _ de _ llamada no válida: la aplicación proporcionó datos de parámetros no válidos.DXGI_ERROR_INVALID_CALL: The application provided invalid parameter data. Si obtienes este error aunque sea una sola vez, significa que el código provocó la condición de dispositivo quitado y debe depurarse.If you get this error even once, it means that your code caused the device removed condition and must be debugged.
  • S _ OK: se devuelve cuando se habilita, deshabilita o restablece un dispositivo de gráficos sin invalidar el dispositivo de gráficos actual.S_OK: Returned when a graphics device was enabled, disabled, or reset without invalidating the current graphics device. Por ejemplo, este código de error puede devolverse si una aplicación está usando Windows Advanced Rasterization Platform (WARP) y un adaptador de hardware se vuelve disponible.For example, this error code can be returned if an app is using Windows Advanced Rasterization Platform (WARP) and a hardware adapter becomes available.

El código siguiente recuperará el código de error del dispositivo de error de DXGI y lo imprimirá en la consola de depuración. ** _ _ _ **The following code will retrieve the DXGI_ERROR_DEVICE_REMOVED error code and print it to the debug console. Inserta este código al comienzo del método HandleDeviceLost.Insert this code at the beginning of the HandleDeviceLost method:

    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.For more details, see GetDeviceRemovedReason and DXGI_ERROR.

Probar el control de dispositivo quitadoTesting Device Removed Handling

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 relacionados con el diagnóstico de gráficos de Visual Studio.Visual Studio's Developer Command Prompt supports a command line tool 'dxcap' for Direct3D event capture and playback related to the Visual Studio Graphics Diagnostics. Puede usar la opción de línea de comandos "-forcetdr" mientras se ejecuta la aplicación, lo que forzará un evento de detección y recuperación del tiempo de espera de la GPU, lo que desencadenará _ el dispositivo de errores de DXGI _ y le _ permitirá probar el código de control de errores.You can use the command line option "-forcetdr" while your app is running which will force a GPU Timeout Detection and Recovery event, thereby triggering DXGI_ERROR_DEVICE_REMOVED and allowing you to test your error handling code.

Nota: DXCap y sus dll de soporte se instalan en system32/SysWow64 como parte de las herramientas de gráficos para Windows 10 que ya no se distribuyen a través del Windows SDK.Note DXCap and its support DLLs are installed into system32/syswow64 as part of the Graphics Tools for Windows 10 which are no longer distributed via the Windows SDK. En su lugar, se proporcionan a través de la característica de herramientas de gráficos a petición que es un componente opcional del sistema operativo, y que debe instalarse para poder habilitar y usar las herramientas de gráficos en Windows 10.Instead they are provided via the Graphics Tools Feature on Demand that is an optional OS component and must be installed in order to enable and use the Graphics Tools on Windows 10. Puedes obtener información sobre cómo instalar las herramientas de gráficos para Windows 10 aquí: https://msdn.microsoft.com/library/mt125501.aspx#InstallGraphicsToolsMore information on how to Install the Graphics Tools for Windows 10 can be found here: https://msdn.microsoft.com/library/mt125501.aspx#InstallGraphicsTools