Partager via


Gérer les scénarios supprimés d’appareils dans Direct3D 11

Cette rubrique explique comment recréer la chaîne d’interface d’appareil Direct3D et DXGI lorsque la carte graphique est supprimée ou réinitialisée.

Dans DirectX 9, les applications peuvent rencontrer une condition de « perte d’appareil » où l’appareil D3D entre dans un état non opérationnel. Par exemple, lorsqu’une application Direct3D 9 en plein écran perd le focus, l’appareil Direct3D devient « perdu ; » toute tentative de dessin avec un appareil perdu échoue silencieusement. Direct3D 11 utilise des interfaces d’appareil graphique virtuel, ce qui permet à plusieurs programmes de partager le même appareil graphique physique et d’éliminer les conditions où les applications perdent le contrôle de l’appareil Direct3D. Toutefois, il est toujours possible que la disponibilité de la carte graphique change. Par exemple :

  • Le pilote graphique est mis à niveau.
  • Le système passe d’un adaptateur graphique d’économie d’alimentation à un adaptateur graphique de performances.
  • L’appareil graphique cesse de répondre et est réinitialisé.
  • Un adaptateur graphique est physiquement attaché ou supprimé.

Lorsque de telles circonstances se produisent, DXGI retourne un code d’erreur indiquant que l’appareil Direct3D doit être réinitialisé et que les ressources d’appareil doivent être recréées. Cette procédure pas à pas explique comment les applications et jeux Direct3D 11 peuvent détecter et répondre à toutes les circonstances où la carte graphique est réinitialisée, supprimée ou modifiée. Les exemples de code sont fournis à partir du modèle d’application DirectX 11 (Windows universel) fourni avec Microsoft Visual Studio 2015.

Instructions

Étape 1 :

Incluez une vérification de l’erreur supprimée de l’appareil dans la boucle de rendu. Présentez l’image en appelant IDXGISwapChain ::P resent (ou Present1, etc.). Vérifiez ensuite s’il a retourné DXGI_ERROR_DEVICE_REMOVED ou DXGI_ERROR_DEVICE_RESET.

Tout d’abord, le modèle stocke le HRESULT retourné par la chaîne d’échange DXGI :

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

Après avoir pris soin de tous les autres travaux de présentation de l’image, le modèle recherche l’erreur supprimée par l’appareil. Si nécessaire, il appelle une méthode pour gérer la condition supprimée de l’appareil :

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

Étape 2 :

Incluez également une vérification de l’erreur supprimée par l’appareil lors de la réponse aux modifications de taille de fenêtre. C’est un bon endroit pour vérifier DXGI_ERROR_DEVICE_REMOVED ou DXGI_ERROR_DEVICE_RESET pour plusieurs raisons :

  • Le redimensionnement de la chaîne d’échange nécessite un appel à l’adaptateur DXGI sous-jacent, qui peut retourner l’erreur supprimée par l’appareil.
  • L’application peut avoir été déplacée vers un moniteur attaché à un autre appareil graphique.
  • Lorsqu’un appareil graphique est supprimé ou réinitialisé, la résolution de bureau change souvent, ce qui entraîne un changement de taille de fenêtre.

Le modèle vérifie le HRESULT retourné par 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);
}

Étape 3 :

Chaque fois que votre application reçoit l’erreur DXGI_ERROR_DEVICE_REMOVED , elle doit réinitialiser l’appareil Direct3D et recréer toutes les ressources dépendantes de l’appareil. Relâchez toutes les références aux ressources d’appareil graphique créées avec l’appareil Direct3D précédent ; ces ressources ne sont plus valides et toutes les références à la chaîne d’échange doivent être libérées avant de pouvoir en créer une nouvelle.

La méthode HandleDeviceLost libère la chaîne d’échange et avertit les composants de l’application de libérer des ressources d’appareil :

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

Ensuite, il crée une chaîne d’échange et réinitialise les ressources dépendantes de l’appareil contrôlées par la classe de gestion des appareils :

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

Une fois que l’appareil et la chaîne d’échange ont été rétablis, il informe les composants de l’application de réinitialiser les ressources dépendantes de l’appareil :

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

Lorsque la méthode HandleDeviceLost se ferme, le contrôle retourne à la boucle de rendu, qui continue à dessiner le cadre suivant.

Notes

Examen de la cause des erreurs supprimées de l’appareil

Les problèmes répétés liés aux erreurs supprimées de l’appareil DXGI peuvent indiquer que votre code graphique crée des conditions non valides pendant une routine de dessin. Il peut également indiquer une défaillance matérielle ou un bogue dans le pilote graphique. Pour examiner la cause des erreurs supprimées de l’appareil, appelez ID3D11Device ::GetDeviceRemovedReason avant de libérer l’appareil Direct3D. Cette méthode retourne l’un des six codes d’erreur DXGI possibles indiquant la raison de l’erreur supprimée par l’appareil :

  • DXGI_ERROR_DEVICE_HUNG : le pilote graphique a cessé de répondre en raison d’une combinaison non valide de commandes graphiques envoyées par l’application. Si vous obtenez cette erreur à plusieurs reprises, il est probable que votre application ait provoqué le blocage de l’appareil et qu’elle doit être déboguée.
  • DXGI_ERROR_DEVICE_REMOVED : le périphérique graphique a été physiquement supprimé, désactivé ou une mise à niveau de pilote s’est produite. Cela se produit occasionnellement et est normal ; votre application ou votre jeu doit recréer des ressources d’appareil, comme décrit dans cette rubrique.
  • DXGI_ERROR_DEVICE_RESET : l’appareil graphique a échoué en raison d’une commande mal formée. Si vous obtenez cette erreur à plusieurs reprises, cela peut signifier que votre code envoie des commandes de dessin non valides.
  • DXGI_ERROR_DRIVER_INTERNAL_ERROR : le pilote graphique a rencontré une erreur et réinitialisé l’appareil.
  • DXGI_ERROR_INVALID_CALL : l’application a fourni des données de paramètre non valides. Si vous obtenez cette erreur même une fois, cela signifie que votre code a provoqué la suppression de l’appareil et doit être débogué.
  • S_OK : retourné lorsqu’un appareil graphique a été activé, désactivé ou réinitialisé sans invalider l’appareil graphique actuel. Par exemple, ce code d’erreur peut être retourné si une application utilise windows Advanced Rasterization Platform (WARP) et qu’une carte matérielle devient disponible.

Le code suivant récupère le code d’erreur DXGI_ERROR_DEVICE_REMOVED et l’imprime dans la console de débogage. Insérez ce code au début de la méthode 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

Pour plus d’informations, consultez GetDeviceRemovedReason et DXGI_ERROR.

Test de la gestion supprimée de l’appareil

L’invite de commandes développeur de Visual Studio prend en charge un outil en ligne de commande « dxcap » pour la capture d’événements Direct3D et la lecture associées aux diagnostics graphiques Visual Studio. Vous pouvez utiliser l’option de ligne de commande « -forcetdr » pendant que votre application est en cours d’exécution, ce qui force un événement de détection et de récupération du délai d’attente GPU, ce qui déclenche DXGI_ERROR_DEVICE_REMOVED et vous permet de tester votre code de gestion des erreurs.

Notez que DXCap et ses DLL de prise en charge sont installées dans system32/syswow64 dans le cadre des outils Graphics pour Windows 10 qui ne sont plus distribués via le Kit de développement logiciel (SDK) Windows. Au lieu de cela, ils sont fournis via la fonctionnalité Graphics Tools à la demande qui est un composant de système d’exploitation facultatif et doit être installé pour activer et utiliser les outils graphiques sur Windows 10. Vous trouverez plus d’informations sur l’installation des outils Graphics pour Windows 10 ici : https://msdn.microsoft.com/library/mt125501.aspx#InstallGraphicsTools