處理 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 app 與遊戲如何能偵測和回應圖形卡重設、移除或變更的情況。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 App (通用 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. 如果重複出現這個錯誤,很可能是您的 app 導致裝置當機,必須對 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. 這是偶爾會發生的正常情況,您的 app 或遊戲需依照本主題的說明來重建裝置資源。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. 例如,如果某個 app 正在使用 Windows Advanced Rasterization Platform (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 _ 錯誤 _ 裝置 _ 移除 的錯誤碼,並將其列印至 debug 主控台。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 的「開發人員命令提示字元」支援針對與 Visual Studio 圖形診斷相關之 Direct3D 事件擷取及播放的命令列工具「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 和其支援的 DLL 會做為「Windows 10 圖形工具」的一部分安裝到 system32/syswow64。「Windows 10 圖形工具」已不再透過 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. 它們是改為以選用 OS 元件的方式,透過「圖形工具」功能隨選安裝提供,且必須安裝才能啟用並使用「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