Behandeln von Szenarien mit entfernten Geräten in Direct3D 11
In diesem Thema wird erläutert, wie Sie die Direct3D- und DXGI-Geräteschnittstellenkette neu erstellen, wenn der Grafikadapter entfernt oder neu initialisiert wird.
In DirectX 9 können Anwendungen auf einen Zustand "Gerät verloren" stoßen, bei dem das D3D-Gerät in einen nicht betriebsfähigen Zustand wechselt. Wenn beispielsweise eine Direct3D 9-Anwendung im Vollbildmodus den Fokus verliert, geht das Direct3D-Gerät "verloren"; alle Versuche, mit einem verlorenen Gerät zu zeichnen, schlagen im Hintergrund fehl. Direct3D 11 verwendet virtuelle Grafikgeräteschnittstellen, sodass mehrere Programme dasselbe physische Grafikgerät gemeinsam nutzen und Bedingungen beseitigen können, unter denen Apps die Kontrolle über das Direct3D-Gerät verlieren. Es ist jedoch weiterhin möglich, dass sich die Verfügbarkeit von Grafikkarten ändert. Zum Beispiel:
- Der Grafiktreiber wird aktualisiert.
- Das System wechselt von einem Energiespargrafikadapter zu einem Leistungsgrafikadapter.
- Das Grafikgerät reagiert nicht mehr und wird zurückgesetzt.
- Ein Grafikadapter ist physisch angeschlossen oder entfernt.
Wenn solche Umstände auftreten, gibt DXGI einen Fehlercode zurück, der angibt, dass das Direct3D-Gerät neu initialisiert werden muss und Geräteressourcen neu erstellt werden müssen. In dieser exemplarischen Vorgehensweise wird erläutert, wie Direct3D 11-Apps und -Spiele alle Umstände erkennen und darauf reagieren können, in denen der Grafikkarte zurückgesetzt, entfernt oder geändert wird. Codebeispiele werden aus der DirectX 11-App-Vorlage (Universelle Windows-App) bereitgestellt, die mit Microsoft Visual Studio 2015 bereitgestellt wird.
Anweisungen
Schritt 1:
Fügen Sie eine Überprüfung auf den Fehler "Gerät entfernt" in die Renderingschleife ein. Präsentieren Sie den Frame, indem Sie IDXGISwapChain::P resent (oder Present1 usw.) aufrufen. Überprüfen Sie dann, ob sie DXGI_ERROR_DEVICE_REMOVED oder DXGI_ERROR_DEVICE_RESET zurückgegeben hat.
Zunächst speichert die Vorlage das von der DXGI-Swapchain zurückgegebene HRESULT:
HRESULT hr = m_swapChain->Present(1, 0);
Nachdem alle anderen Arbeiten für die Darstellung des Frames durchgeführt wurden, sucht die Vorlage nach dem Fehler "Gerät entfernt". Bei Bedarf ruft sie eine Methode zum Behandeln der zustandsfernten Geräte auf:
// 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);
}
Schritt 2:
Schließen Sie außerdem eine Überprüfung auf den Fehler "Gerät entfernt" ein, wenn Sie auf Änderungen der Fenstergröße reagieren. Dies ist ein guter Ort, um aus verschiedenen Gründen nach DXGI_ERROR_DEVICE_REMOVED oder DXGI_ERROR_DEVICE_RESET zu suchen:
- Das Ändern der Größe der Swapchain erfordert einen Aufruf des zugrunde liegenden DXGI-Adapters, der den Fehler "Gerät entfernt" zurückgeben kann.
- Die App wurde möglicherweise auf einen Monitor verschoben, der an ein anderes Grafikgerät angeschlossen ist.
- Wenn ein Grafikgerät entfernt oder zurückgesetzt wird, ändert sich die Desktopauflösung häufig, was zu einer Änderung der Fenstergröße führt.
Die Vorlage überprüft das von ResizeBuffers zurückgegebene HRESULT:
// 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);
}
Schritt 3:
Jedes Mal, wenn Ihre App den DXGI_ERROR_DEVICE_REMOVED Fehler empfängt, muss sie das Direct3D-Gerät neu initialisieren und alle geräteabhängigen Ressourcen neu erstellen. Geben Sie verweise auf Grafikgeräteressourcen frei, die mit dem vorherigen Direct3D-Gerät erstellt wurden; diese Ressourcen sind jetzt ungültig, und alle Verweise auf die Swapchain müssen freigegeben werden, bevor eine neue erstellt werden kann.
Die HandleDeviceLost-Methode gibt die Swapchain frei und benachrichtigt App-Komponenten, geräteressourcen freizugeben:
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();
}
Anschließend wird eine neue Swapchain erstellt und die geräteabhängigen Ressourcen neu initialisiert, die von der Geräteverwaltungsklasse gesteuert werden:
// Create the new device and swap chain.
CreateDeviceResources();
m_d2dContext->SetDpi(m_dpi, m_dpi);
CreateWindowSizeDependentResources();
Nachdem das Gerät und die Swapchain neu eingerichtet wurden, werden App-Komponenten benachrichtigt, geräteabhängige Ressourcen neu zu initialisieren:
// 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();
}
Wenn die HandleDeviceLost-Methode beendet wird, kehrt das Steuerelement zur Renderingschleife zurück, wodurch der nächste Frame weiterhin gezeichnet wird.
Hinweise
Untersuchen der Ursache für geräteferne Fehler
Wiederholte Probleme mit DXGI-Geräten entfernten Fehlern können darauf hinweisen, dass der Grafikcode während einer Zeichnungsroutine ungültige Bedingungen erstellt. Sie kann auch auf einen Hardwarefehler oder einen Fehler im Grafiktreiber hinweisen. Rufen Sie ID3D11Device::GetDeviceRemovedReason auf, um die Ursache von Gerätefehlern zu untersuchen, bevor Sie das Direct3D-Gerät freigeben. Diese Methode gibt einen von sechs möglichen DXGI-Fehlercodes zurück, der den Grund für den Fehler "Gerät entfernt" angibt:
- DXGI_ERROR_DEVICE_HUNG: Der Grafiktreiber reagierte aufgrund einer ungültigen Kombination von Grafikbefehlen, die von der App gesendet wurden. Wenn dieser Fehler wiederholt angezeigt wird, ist es wahrscheinlich ein Hinweis darauf, dass die App das Gerät hängen ließ und gedebuggt werden muss.
- DXGI_ERROR_DEVICE_REMOVED: Das Grafikgerät wurde physisch entfernt, deaktiviert oder es ist ein Treiberupgrade aufgetreten. Dies geschieht gelegentlich und ist normal; Ihre App oder Ihr Spiel sollte Geräteressourcen neu erstellen, wie in diesem Thema beschrieben.
- DXGI_ERROR_DEVICE_RESET: Fehler des Grafikgeräts aufgrund eines fehlerhaften Befehls. Wenn dieser Fehler wiederholt angezeigt wird, bedeutet dies möglicherweise, dass Ihr Code ungültige Zeichnungsbefehle sendet.
- DXGI_ERROR_DRIVER_INTERNAL_ERROR: Der Grafiktreiber hat einen Fehler festgestellt und das Gerät zurückgesetzt.
- DXGI_ERROR_INVALID_CALL: Die Anwendung hat ungültige Parameterdaten bereitgestellt. Wenn dieser Fehler auch einmal angezeigt wird, bedeutet dies, dass ihr Code die Bedingung für das Gerät entfernt hat und debuggt werden muss.
- S_OK: Wird zurückgegeben, wenn ein Grafikgerät aktiviert, deaktiviert oder zurückgesetzt wurde, ohne das aktuelle Grafikgerät ungültig zu machen. Dieser Fehlercode kann beispielsweise zurückgegeben werden, wenn eine App windows Advanced Rasterization Platform (WARP) verwendet und ein Hardwareadapter verfügbar wird.
Der folgende Code ruft den DXGI_ERROR_DEVICE_REMOVED Fehlercode ab und druckt ihn in der Debugkonsole. Fügen Sie diesen Code am Anfang der HandleDeviceLost-Methode ein:
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
Weitere Informationen finden Sie unter GetDeviceRemovedReason und DXGI_ERROR.
Testen der entfernten Behandlung von Geräten
Die Entwickler-Eingabeaufforderung von Visual Studio unterstützt ein Befehlszeilentool "dxcap" für die Direct3D-Ereigniserfassung und -wiedergabe im Zusammenhang mit der Visual Studio-Grafikdiagnose. Sie können die Befehlszeilenoption "-forcetdr" verwenden, während Ihre App ausgeführt wird, wodurch ein GPU-Timeouterkennungs- und Wiederherstellungsereignis erzwungen wird, wodurch DXGI_ERROR_DEVICE_REMOVED ausgelöst und Der Fehlerbehandlungscode getestet werden kann.
Beachten Sie, dass DXCap und seine Support-DLLs im System32/syswow64 als Teil der Grafiktools für Windows 10 installiert sind, die nicht mehr über das Windows SDK verteilt werden. Stattdessen werden sie über das Feature "Grafiktools bei Bedarf" bereitgestellt, das eine optionale Betriebssystemkomponente ist und installiert werden muss, um die Grafiktools unter Windows 10 zu aktivieren und zu verwenden. Weitere Informationen zum Installieren der Grafiktools für Windows 10 finden Sie hier: https://msdn.microsoft.com/library/mt125501.aspx#InstallGraphicsTools