Lidar com cenários removidos do dispositivo no Direct3D 11
Este tópico explica como recriar a cadeia de interface do dispositivo Direct3D e DXGI quando o adaptador gráfico é removido ou reinicializado.
No DirectX 9, os aplicativos podem encontrar uma condição de "dispositivo perdido" em que o dispositivo D3D entra em um estado não operacional. Por exemplo, quando um aplicativo Direct3D 9 de tela inteira perde o foco, o dispositivo Direct3D fica "perdido"; qualquer tentativa de desenhar com um dispositivo perdido falhará silenciosamente. O Direct3D 11 usa interfaces de dispositivo gráfico virtual, permitindo que vários programas compartilhem o mesmo dispositivo gráfico físico e eliminando condições em que os aplicativos perdem o controle do dispositivo Direct3D. No entanto, ainda é possível que a disponibilidade do adaptador gráfico seja alterada. Por exemplo:
- O driver gráfico é atualizado.
- O sistema muda de um adaptador gráfico de economia de energia para um adaptador gráfico de desempenho.
- O dispositivo gráfico para de responder e é redefinido.
- Um adaptador gráfico é fisicamente conectado ou removido.
Quando essas circunstâncias surgem, o DXGI retorna um código de erro indicando que o dispositivo Direct3D deve ser reinicializado e os recursos do dispositivo devem ser recriados. Este passo a passo explica como os aplicativos e jogos do Direct3D 11 podem detectar e responder a qualquer circunstância em que o adaptador gráfico seja redefinido, removido ou alterado. Exemplos de código são fornecidos do modelo de aplicativo DirectX 11 (Universal Windows) fornecido com o Microsoft Visual Studio 2015.
Instruções
Etapa 1:
Inclua uma verificação do erro de dispositivo removido no loop de renderização. Apresente o quadro chamando IDXGISwapChain::P resent (ou Present1 e assim por diante). Em seguida, verifique se ele retornou DXGI_ERROR_DEVICE_REMOVED ou DXGI_ERROR_DEVICE_RESET.
Primeiro, o modelo armazena o HRESULT retornado pela cadeia de troca DXGI:
HRESULT hr = m_swapChain->Present(1, 0);
Depois de cuidar de todos os outros trabalhos de apresentação do quadro, o modelo verifica o erro removido do dispositivo. Se necessário, ele chama um método para lidar com a condição de remoção do dispositivo:
// 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);
}
Etapa 2:
Além disso, inclua uma verificação do erro de remoção do dispositivo ao responder a alterações de tamanho da janela. Este é um bom lugar para verificar se há DXGI_ERROR_DEVICE_REMOVED ou DXGI_ERROR_DEVICE_RESET por vários motivos:
- O redimensionamento da cadeia de troca requer uma chamada para o adaptador DXGI subjacente, que pode retornar o erro removido do dispositivo.
- O aplicativo pode ter sido movido para um monitor conectado a um dispositivo gráfico diferente.
- Quando um dispositivo gráfico é removido ou redefinido, a resolução da área de trabalho geralmente muda, resultando em uma alteração no tamanho da janela.
O modelo verifica o HRESULT retornado por 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);
}
Etapa 3:
Sempre que seu aplicativo receber o erro DXGI_ERROR_DEVICE_REMOVED , ele deverá reinicializar o dispositivo Direct3D e recriar todos os recursos dependentes do dispositivo. Libere todas as referências a recursos de dispositivo gráfico criados com o dispositivo Direct3D anterior; Esses recursos agora são inválidos e todas as referências à cadeia de troca devem ser liberadas antes que uma nova possa ser criada.
O método HandleDeviceLost libera a cadeia de troca e notifica os componentes do aplicativo para liberar recursos do dispositivo:
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();
}
Em seguida, ele cria uma nova cadeia de troca e reinicializa os recursos dependentes do dispositivo controlados pela classe de gerenciamento do dispositivo:
// Create the new device and swap chain.
CreateDeviceResources();
m_d2dContext->SetDpi(m_dpi, m_dpi);
CreateWindowSizeDependentResources();
Depois que o dispositivo e a cadeia de troca forem restabelecidos, ele notificará os componentes do aplicativo para reinicializar os recursos dependentes do dispositivo:
// 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();
}
Quando o método HandleDeviceLost é encerrado, o controle retorna ao loop de renderização, que continua a desenhar o próximo quadro.
Comentários
Investigando a causa dos erros removidos do dispositivo
Problemas repetidos com erros removidos do dispositivo DXGI podem indicar que o código gráfico está criando condições inválidas durante uma rotina de desenho. Também pode indicar uma falha de hardware ou um bug no driver gráfico. Para investigar a causa dos erros removidos do dispositivo, chame ID3D11Device::GetDeviceRemovedReason antes de liberar o dispositivo Direct3D. Este método retorna um dos seis códigos de erro DXGI possíveis indicando o motivo do erro removido do dispositivo:
- DXGI_ERROR_DEVICE_HUNG: O driver gráfico parou de responder devido a uma combinação inválida de comandos gráficos enviados pelo aplicativo. Se você receber esse erro repetidamente, é uma indicação provável de que seu aplicativo fez com que o dispositivo travasse e precisa ser depurado.
- DXGI_ERROR_DEVICE_REMOVED: O dispositivo gráfico foi removido fisicamente, desligado ou ocorreu uma atualização de driver. Isso acontece ocasionalmente e é normal; Seu aplicativo ou jogo deve recriar os recursos do dispositivo conforme descrito neste tópico.
- DXGI_ERROR_DEVICE_RESET: O dispositivo gráfico falhou devido a um comando mal formado. Se você receber esse erro repetidamente, isso pode significar que seu código está enviando comandos de desenho inválidos.
- DXGI_ERROR_DRIVER_INTERNAL_ERROR: O driver gráfico encontrou um erro e redefiniu o dispositivo.
- DXGI_ERROR_INVALID_CALL: O aplicativo forneceu dados de parâmetro inválidos. Se você receber esse erro pelo menos uma vez, isso significa que seu código causou a condição de remoção do dispositivo e deve ser depurado.
- S_OK: Retornado quando um dispositivo gráfico foi ativado, desativado ou redefinido sem invalidar o dispositivo gráfico atual. Por exemplo, esse código de erro poderá ser retornado se um aplicativo estiver usando a Plataforma de Rasterização Avançada do Windows (WARP) e um adaptador de hardware estiver disponível.
O código a seguir recuperará o código de erro DXGI_ERROR_DEVICE_REMOVED e o imprimirá no console de depuração. Insira este código no início do método 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
Para obter mais detalhes, consulte GetDeviceRemovedReason e DXGI_ERROR.
Dispositivo de teste removido Manipulação
O Prompt de Comando do Desenvolvedor do Visual Studio dá suporte a uma ferramenta de linha de comando 'dxcap' para captura e reprodução de eventos Direct3D relacionados ao Diagnóstico de Gráficos do Visual Studio. Você pode usar a opção de linha de comando "-forcetdr" enquanto seu aplicativo está em execução, o que forçará um evento de detecção e recuperação de tempo limite da GPU, acionando DXGI_ERROR_DEVICE_REMOVED e permitindo que você teste seu código de tratamento de erros.
Observação : o DXCap e suas DLLs de suporte são instalados em system32/syswow64 como parte das Ferramentas Gráficas para Windows 10, que não são mais distribuídas por meio do SDK do Windows. Em vez disso, eles são fornecidos por meio do recurso de ferramentas gráficas sob demanda, que é um componente opcional do sistema operacional e deve ser instalado para habilitar e usar as ferramentas gráficas no Windows 10. Mais informações sobre como instalar as ferramentas gráficas para Windows 10 podem ser encontradas aqui: https://msdn.microsoft.com/library/mt125501.aspx#InstallGraphicsTools