在 Direct3D 11 中处理设备删除方案Handle device removed scenarios in Direct3D 11

本主题介绍了图形适配器被删除或重新初始化时,如何重新创建 Direct3D 和 DXGI 的设备界面链。This topic explains how to recreate the Direct3D and DXGI device interface chain when the graphics adapter is removed or reinitialized.

在 DirectX 9 中,应用程序可能会遇到“设备丢失”状况,在该情况下,D3D 设备会进入非可操作状态。In DirectX 9, applications could encounter a "device lost" condition where the D3D device enters a non-operational state. 例如,当全屏 Direct3D 9 应用程序失去焦点且 Direct3D 设备变为“已丢失”时,使用丢失设备进行绘制的任何尝试都将静默失败。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 使用虚拟图形设备界面,这使多个程序可以共享相同的物理图形设备,并可以解除应用无法控制 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. 但是,图形适配器可用性仍可能发生更改。However, it is still possible for graphics adapter availability to change. 例如:For example:

  • 图形驱动程序已升级。The graphics driver is upgraded.
  • 系统从节能图形适配器更改为性能图形适配器。The system changes from a power-saving graphics adapter to a performance graphics adapter.
  • 图形设备停止响应并进行重置。The graphics device stops responding and is reset.
  • 已采用物理方式附加或删除图形适配器。A graphics adapter is physically attached or removed.

出现此情况时,DXGI 将返回一个错误代码,该代码指示必须重新初始化 Direct3D 设备且必须重新创建设备资源。When such circumstances arise, DXGI returns an error code indicating that the Direct3D device must be reinitialized and device resources must be recreated. 此操作实例演示了 Direct3D 11 应用和游戏如何检测和响应以下情况:重置、删除或更改图形适配器。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. 随 Microsoft Visual Studio 2015 一起提供的 DirectX 11 应用(通用 Windows)模板提供了代码示例。Code examples are provided from the DirectX 11 App (Universal Windows) template provided with Microsoft Visual Studio 2015.

InstructionsInstructions

步骤 1:Step 1:

包含用于呈现循环中设备删除错误的检查。Include a check for the device removed error in the rendering loop. 通过调用 IDXGISwapChain::Present(或 Present1 等)呈现帧。Present the frame by calling IDXGISwapChain::Present (or Present1, and so on). 然后,检查它是否返回了 dxgi 错误设备,或是否 _ _ _ 已删除 **dxgi _ 错误 _ 设备 _ **。Then, check whether it returned DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET.

首先,模板存储由 DXGI 交换链返回的 HRESULT:First, the template stores the HRESULT returned by the DXGI swap chain:

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

完成呈现帧的所有其他工作后,模板将检查设备删除错误。After taking care of all other work for presenting the frame, the template checks for the device removed error. 如果需要,它将调用某个方法来处理设备删除状况: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);
}

步骤 2:Step 2:

还包含用于在响应窗口大小更改时出现的设备删除错误的检查。Also, include a check for the device removed error when responding to window size changes. 这是一个用于检查是否 ** _ _ _ 已删除 dxgi 错误设备** 或发生了 dxgi _ 错误 _ 设备 _ 重置 的良好位置,原因如下:This is a good place to check for DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET for several reasons:

  • 调整交换链大小需要调用基础 DXGI 适配器,该适配器可以返回设备删除错误。Resizing the swap chain requires a call to the underlying DXGI adapter, which can return the device removed error.
  • 该应用可能已移动到附加到不同图形设备的监视器中。The app might have moved to a monitor that's attached to a different graphics device.
  • 删除或重置图形设备后,桌面分辨率通常发生更改,从而导致窗口大小更改。When a graphics device is removed or reset, the desktop resolution often changes, resulting in a window size change.

模板将检查由 ResizeBuffers 返回的 HRESULT: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);
}

步骤 3:Step 3:

当应用收到 " DXGI _ 错误 _ 设备 _ 已删除 " 错误时,它必须重新初始化 Direct3D 设备,并重新创建与设备相关的任何资源。Any time your app receives the DXGI_ERROR_DEVICE_REMOVED error, it must reinitialize the Direct3D device and recreate any device-dependent resources. 释放对使用早期 Direct3D 设备创建的图形设备资源的任何引用;这些资源现在无效,在创建新交换链之前,必须释放对交换链的所有引用。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.

HandleDeviceLost 方法释放交换链并通知应用组件释放设备资源: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();
}

然后,它将创建一个新交换链,并重新初始化由设备管理类控制的依赖设备的资源: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();

重新建立设备和交换链后,它将通知应用组件重新初始化依赖设备的资源: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();
}

当 HandleDeviceLost 方法退出时,控制将返回到呈现循环,该循环将继续绘制下一个帧。When the HandleDeviceLost method exits, control returns to the rendering loop, which continues on to draw the next frame.

备注Remarks

调查设备删除错误的原因Investigating the cause of device removed errors

如果重复出现带有 DXGI 设备删除错误的问题,这可能指示你的图像代码在绘制例程期间创建的条件无效。Repeat issues with DXGI device removed errors can indicate that your graphics code is creating invalid conditions during a drawing routine. 它还可能指示硬件失败或图形驱动程序中的错误。It can also indicate a hardware failure or a bug in the graphics driver. 若要调查设备删除错误的原因,请调用 ID3D11Device::GetDeviceRemovedReason,然后再释放 Direct3D 设备。To investigate the cause of device removed errors, call ID3D11Device::GetDeviceRemovedReason before releasing the Direct3D device. 此方法返回六个可能的 DXGI 错误代码之一,指示设备删除错误的原因:This method returns one of six possible DXGI error codes indicating the reason for the device removed error:

  • DXGI __设备 _ 挂起错误:由于应用发送的图形命令组合无效,图形驱动程序停止响应。DXGI_ERROR_DEVICE_HUNG: The graphics driver stopped responding because of an invalid combination of graphics commands sent by the app. 如果你反复收到此错误,这可能指示你的应用导致设备挂起,并且需要进行调试。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 __ _ 删除设备时出现错误:图形设备已被物理删除、关闭或驱动程序升级。DXGI_ERROR_DEVICE_REMOVED: The graphics device has been physically removed, turned off, or a driver upgrade has occurred. 这种情况偶尔发生,实属正常情况;你的应用和游戏应重新创建设备资源,如本主题中所述。This happens occasionally and is normal; your app or game should recreate device resources as described in this topic.
  • DXGI __设备 _ 重置错误:图形设备因命令格式错误而失败。DXGI_ERROR_DEVICE_RESET: The graphics device failed because of a badly formed command. 如果你反复收到此错误,这可能意味着你的代码发送的绘制命令无效。If you get this error repeatedly, it may mean that your code is sending invalid drawing commands.
  • DXGI _错误 _ 驱动程序 _ 内部 _ 错误:图形驱动程序遇到错误,请重置设备。DXGI_ERROR_DRIVER_INTERNAL_ERROR: The graphics driver encountered an error and reset the device.
  • DXGI _错误 _ _ 调用无效:应用程序提供的参数数据无效。DXGI_ERROR_INVALID_CALL: The application provided invalid parameter data. 如果你收到过一次此错误,这意味着你的代码导致了设备删除状况,必须进行调试。If you get this error even once, it means that your code caused the device removed condition and must be debugged.
  • S _确定:在启用、禁用或重置图形设备时,如果不使当前图形设备失效,则返回。S_OK: Returned when a graphics device was enabled, disabled, or reset without invalidating the current graphics device. 例如,如果应用使用的是 Windows 高级光栅化平台 (WARP) 且硬件适配器变为可用,则可能返回此错误代码。For example, this error code can be returned if an app is using Windows Advanced Rasterization Platform (WARP) and a hardware adapter becomes available.

以下代码将检索 " DXGI _ 错误 _ 设备 _ 已删除 " 错误代码,并将其打印到调试控制台。The following code will retrieve the DXGI_ERROR_DEVICE_REMOVED error code and print it to the debug console. 将此代码插入 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

有关更多详细信息,请参阅 GetDeviceRemovedReasonDXGI _ 错误For more details, see GetDeviceRemovedReason and DXGI_ERROR.

测试设备删除处理Testing Device Removed Handling

对于与 Visual Studio 图形诊断相关的 Direct3D 事件捕获和播放,Visual Studio 开发人员命令提示符支持命令行工具“dxcap”。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. 当应用运行时,可以使用命令行选项 "-forcetdr",它将强制执行 GPU 超时检测和恢复事件,从而触发删除 DXGI _ 错误 _ 设备, _ 并允许你测试错误处理代码。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.

注意 Dxcap.exe 及其支持 Dll 作为 Windows 10 的图形工具的一部分安装到 system32/syswow64,这些工具不再通过 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. 不过,它们将通过图形工具按需功能(它是可选的操作系统组件)进行提供,并且必须先进行安装,然后才能启用并使用 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. 有关如何安装适用于 Windows 10 的图形工具的详细信息,请参阅: 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