Menangani skenario yang dihapus perangkat di Direct3D 11

Topik ini menjelaskan cara membuat ulang rantai antarmuka perangkat Direct3D dan DXGI saat adaptor grafis dihapus atau diinisialisasi ulang.

Di DirectX 9, aplikasi dapat mengalami kondisi "perangkat hilang" di mana perangkat D3D memasuki status tidak beroperasi. Misalnya, ketika aplikasi Direct3D 9 layar penuh kehilangan fokus, perangkat Direct3D menjadi "hilang;" setiap upaya untuk menggambar dengan perangkat yang hilang akan gagal secara diam-diam. Direct3D 11 menggunakan antarmuka perangkat grafis virtual, memungkinkan beberapa program untuk berbagi perangkat grafis fisik yang sama dan menghilangkan kondisi di mana aplikasi kehilangan kontrol perangkat Direct3D. Namun, ketersediaan adaptor grafis masih dapat berubah. Contohnya:

  • Driver grafis ditingkatkan.
  • Sistem berubah dari adaptor grafis hemat daya ke adaptor grafis performa.
  • Perangkat grafis berhenti merespons dan direset.
  • Adaptor grafis dilampirkan atau dihapus secara fisik.

Ketika keadaan seperti itu muncul, DXGI mengembalikan kode kesalahan yang menunjukkan bahwa perangkat Direct3D harus diinisialisasi ulang dan sumber daya perangkat harus dibuat ulang. Panduan ini menjelaskan bagaimana aplikasi dan game Direct3D 11 dapat mendeteksi dan merespons keadaan apa pun di mana adaptor grafis diatur ulang, dihapus, atau diubah. Contoh kode disediakan dari templat Aplikasi DirectX 11 (Universal Windows) yang disediakan dengan Microsoft Visual Studio 2015.

Petunjuk

Langkah 1:

Sertakan pemeriksaan untuk kesalahan perangkat yang dihapus dalam perulangan penyajian. Sajikan bingkai dengan memanggil IDXGISwapChain::P resent (atau Present1, dan sebagainya). Kemudian, periksa apakah dikembalikan DXGI_ERROR_DEVICE_REMOVED atau DXGI_ERROR_DEVICE_RESET.

Pertama, templat menyimpan HRESULT yang dikembalikan oleh rantai pertukaran DXGI:

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

Setelah mengurus semua pekerjaan lain untuk menyajikan bingkai, templat memeriksa kesalahan perangkat yang dihapus. Jika perlu, ini memanggil metode untuk menangani kondisi perangkat yang dihapus:

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

Langkah 2:

Selain itu, sertakan pemeriksaan kesalahan perangkat yang dihapus saat merespons perubahan ukuran jendela. Ini adalah tempat yang baik untuk memeriksa DXGI_ERROR_DEVICE_REMOVED atau DXGI_ERROR_DEVICE_RESET karena beberapa alasan:

  • Mengubah ukuran rantai pertukaran memerlukan panggilan ke adaptor DXGI yang mendasar, yang dapat mengembalikan kesalahan yang dihapus perangkat.
  • Aplikasi mungkin telah dipindahkan ke monitor yang dilampirkan ke perangkat grafis yang berbeda.
  • Saat perangkat grafis dihapus atau direset, resolusi desktop sering berubah, sehingga ukuran jendela berubah.

Templat memeriksa HRESULT yang dikembalikan oleh 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);
}

Langkah 3:

Setiap kali aplikasi Anda menerima kesalahan DXGI_ERROR_DEVICE_REMOVED , aplikasi harus menginisialisasi ulang perangkat Direct3D dan membuat ulang sumber daya yang bergantung pada perangkat. Merilis referensi apa pun ke sumber daya perangkat grafis yang dibuat dengan perangkat Direct3D sebelumnya; sumber daya tersebut sekarang tidak valid, dan semua referensi ke rantai pertukaran harus dirilis sebelum sumber daya baru dapat dibuat.

Metode HandleDeviceLost merilis rantai pertukaran dan memberi tahu komponen aplikasi untuk merilis sumber daya perangkat:

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

Kemudian, ini membuat rantai pertukaran baru dan menginisialisasi ulang sumber daya yang bergantung pada perangkat yang dikendalikan oleh kelas manajemen perangkat:

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

Setelah perangkat dan rantai pertukaran dibuat kembali, perangkat akan memberi tahu komponen aplikasi untuk menginisialisasi ulang sumber daya yang bergantung pada perangkat:

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

Ketika metode HandleDeviceLost keluar, kontrol kembali ke perulangan penyajian, yang berlanjut untuk menggambar bingkai berikutnya.

Keterangan

Menyelidiki penyebab kesalahan perangkat dihapus

Mengulangi masalah dengan kesalahan yang dihapus perangkat DXGI dapat menunjukkan bahwa kode grafis Anda membuat kondisi yang tidak valid selama rutinitas menggambar. Ini juga dapat menunjukkan kegagalan perangkat keras atau bug di driver grafis. Untuk menyelidiki penyebab kesalahan perangkat dihapus, panggil ID3D11Device::GetDeviceRemovedReason sebelum merilis perangkat Direct3D. Metode ini mengembalikan salah satu dari enam kemungkinan kode kesalahan DXGI yang menunjukkan alasan kesalahan penghapusan perangkat:

  • DXGI_ERROR_DEVICE_HUNG: Driver grafis berhenti merespons karena kombinasi perintah grafis yang tidak valid yang dikirim oleh aplikasi. Jika Anda mendapatkan kesalahan ini berulang kali, kemungkinan itu adalah indikasi bahwa aplikasi Anda menyebabkan perangkat macet dan perlu di-debug.
  • DXGI_ERROR_DEVICE_REMOVED: Perangkat grafis telah dihapus secara fisik, dimatikan, atau peningkatan driver telah terjadi. Ini terjadi sesekali dan normal; aplikasi atau game Anda harus membuat ulang sumber daya perangkat seperti yang dijelaskan dalam topik ini.
  • DXGI_ERROR_DEVICE_RESET: Perangkat grafis gagal karena perintah yang terbentuk dengan buruk. Jika Anda mendapatkan kesalahan ini berulang kali, itu mungkin berarti bahwa kode Anda mengirim perintah gambar yang tidak valid.
  • DXGI_ERROR_DRIVER_INTERNAL_ERROR: Driver grafis mengalami kesalahan dan mengatur ulang perangkat.
  • DXGI_ERROR_INVALID_CALL: Aplikasi menyediakan data parameter yang tidak valid. Jika Anda mendapatkan kesalahan ini bahkan sekali, itu berarti bahwa kode Anda menyebabkan kondisi perangkat dihapus dan harus di-debug.
  • S_OK: Dikembalikan saat perangkat grafis diaktifkan, dinonaktifkan, atau direset tanpa membatalkan perangkat grafis saat ini. Misalnya, kode kesalahan ini dapat dikembalikan jika aplikasi menggunakan Windows Advanced Rasterization Platform (WARP) dan adaptor perangkat keras tersedia.

Kode berikut akan mengambil kode kesalahan DXGI_ERROR_DEVICE_REMOVED dan mencetaknya ke konsol debug. Sisipkan kode ini di awal metode 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

Untuk detail selengkapnya, lihat GetDeviceRemovedReason dan DXGI_ERROR.

Menguji Penanganan Perangkat yang Dihapus

Prompt Perintah Pengembang Visual Studio mendukung alat baris perintah 'dxcap' untuk pengambilan dan pemutaran peristiwa Direct3D yang terkait dengan Diagnostik Grafis Visual Studio. Anda dapat menggunakan opsi baris perintah "-forcetdr" saat aplikasi Anda berjalan yang akan memaksa peristiwa Deteksi dan Pemulihan Batas Waktu GPU, sehingga memicu DXGI_ERROR_DEVICE_REMOVED dan memungkinkan Anda menguji kode penanganan kesalahan Anda.

Catatan DXCap dan DLL dukungannya diinstal ke sistem32/syswow64 sebagai bagian dari Alat Grafis untuk Windows 10 yang tidak lagi didistribusikan melalui Windows SDK. Sebaliknya mereka disediakan melalui Fitur Alat Grafis sesuai Permintaan yang merupakan komponen OS opsional dan harus diinstal untuk mengaktifkan dan menggunakan Alat Grafis di Windows 10. Informasi selengkapnya tentang cara Menginstal Alat Grafis untuk Windows 10 dapat ditemukan di sini:https://msdn.microsoft.com/library/mt125501.aspx#InstallGraphicsTools