Pemrograman asinkron (DirectX dan C++)

Topik ini mencakup berbagai poin yang perlu dipertimbangkan ketika Anda menggunakan pemrograman dan utas asinkron dengan DirectX.

Pemrograman asinkron dan DirectX

Jika Anda hanya belajar tentang DirectX, atau bahkan jika Anda berpengalaman dengannya, pertimbangkan untuk menempatkan semua alur pemrosesan grafis Anda pada satu utas. Dalam adegan tertentu dalam game, ada sumber daya umum seperti bitmap, shader, dan aset lain yang memerlukan akses eksklusif. Sumber daya yang sama ini mengharuskan Anda menyinkronkan akses apa pun ke sumber daya ini di seluruh utas paralel. Penyajian adalah proses yang sulit untuk diparalelkan di beberapa utas.

Namun, jika gim Anda cukup kompleks, atau jika Anda ingin meningkatkan performa, Anda dapat menggunakan pemrograman asinkron untuk menyejajarkan beberapa komponen yang tidak spesifik untuk alur penyajian Anda. Perangkat keras modern memiliki beberapa CPU inti dan hyperthreaded, dan aplikasi Anda harus memanfaatkan ini! Anda dapat memastikan ini dengan menggunakan pemrograman asinkron untuk beberapa komponen game Anda yang tidak memerlukan akses langsung ke konteks perangkat Direct3D, seperti:

  • I/O file
  • fisika
  • AI
  • jaringan
  • audio
  • controls
  • Komponen UI berbasis XAML

Aplikasi Anda dapat menangani komponen ini pada beberapa utas bersamaan. I/O file, terutama pemuatan aset, sangat diuntungkan dari pemuatan asinkron, karena game atau aplikasi Anda dapat berada dalam keadaan interaktif sementara beberapa (atau beberapa ratus) megabyte aset sedang dimuat atau dialirkan. Cara term mudah untuk membuat dan mengelola utas ini adalah dengan menggunakan Pustaka Pola Paralel dan pola tugas , seperti yang terkandung dalam namespace layanan konkurensi yang ditentukan dalam PPLTasks.h. Menggunakan Pustaka Pola Paralel memanfaatkan secara langsung beberapa CPU inti dan hyperthreaded, dan dapat meningkatkan semuanya mulai dari waktu pemuatan yang dirasakan hingga hitche dan jeda yang dilengkapi dengan perhitungan CPU intensif atau pemrosesan jaringan.

Catatan Dalam aplikasi Platform Windows Universal (UWP), antarmuka pengguna berjalan sepenuhnya di apartemen berulir tunggal (STA). Jika Anda membuat UI untuk game DirectX Anda menggunakan interop XAML, Anda hanya dapat mengakses kontrol dengan menggunakan STA.

 

Multithreading dengan perangkat Direct3D

Multithreading untuk konteks perangkat hanya tersedia di perangkat grafis yang mendukung tingkat fitur Direct3D 11_0 atau yang lebih baru. Namun, Anda mungkin ingin memaksimalkan penggunaan GPU yang kuat di banyak platform, seperti platform game khusus. Dalam kasus paling sederhana, Anda mungkin ingin memisahkan penyajian overlay tampilan heads-up (HUD) dari rendering dan proyeksi adegan 3D dan meminta kedua komponen menggunakan alur paralel terpisah. Kedua utas harus menggunakan ID3D11DeviceContext yang sama untuk membuat dan mengelola objek sumber daya (tekstur, jala, shader, dan aset lainnya), yang merupakan utas tunggal, dan yang mengharuskan Anda menerapkan semacam mekanisme sinkronisasi (seperti bagian penting) untuk mengaksesnya dengan aman. Dan, meskipun Anda dapat membuat daftar perintah terpisah untuk konteks perangkat pada utas yang berbeda (untuk penyajian yang ditangguhkan), Anda tidak dapat memutar daftar perintah tersebut secara bersamaan pada instans ID3D11DeviceContext yang sama.

Sekarang, aplikasi Anda juga dapat menggunakan ID3D11Device, yang aman untuk multithreading, untuk membuat objek sumber daya. Jadi, mengapa tidak selalu menggunakan ID3D11Device alih-alih ID3D11DeviceContext? Nah, saat ini, dukungan driver untuk multithreading mungkin tidak tersedia untuk beberapa antarmuka grafis. Anda dapat mengkueri perangkat dan mencari tahu apakah perangkat tersebut mendukung multithreading, tetapi jika Anda ingin menjangkau audiens terluas, Anda mungkin tetap menggunakan ID3D11DeviceContext untuk manajemen objek sumber daya. Meskipun demikian, ketika driver perangkat grafis tidak mendukung daftar multithreading atau perintah, Direct3D 11 mencoba menangani akses yang disinkronkan ke konteks perangkat secara internal; dan jika daftar perintah tidak didukung, itu menyediakan implementasi perangkat lunak. Akibatnya, Anda dapat menulis kode multithreaded yang akan berjalan pada platform dengan antarmuka grafis yang tidak memiliki dukungan driver untuk akses konteks perangkat multithreaded.

Jika aplikasi Anda mendukung utas terpisah untuk memproses daftar perintah dan untuk menampilkan bingkai, Anda mungkin ingin menjaga GPU tetap aktif, memproses daftar perintah saat menampilkan bingkai secara tepat waktu tanpa gagap atau jeda yang terlihat. Dalam hal ini, Anda dapat menggunakan ID3D11DeviceContext terpisah untuk setiap utas, dan untuk berbagi sumber daya (seperti tekstur) dengan membuatnya dengan bendera D3D11_RESOURCE_MISC_SHARED. Dalam skenario ini, ID3D11DeviceContext::Flush harus dipanggil pada utas pemrosesan untuk menyelesaikan eksekusi daftar perintah sebelum menampilkan hasil pemrosesan objek sumber daya di utas tampilan.

Penyajian yang ditangguhkan

Perintah grafik rekaman rendering yang ditangguhkan dalam daftar perintah sehingga dapat diputar kembali di lain waktu, dan dirancang untuk mendukung penyajian pada satu utas saat merekam perintah untuk penyajian pada utas tambahan. Setelah perintah ini selesai, perintah dapat dijalankan pada utas yang menghasilkan objek tampilan akhir (buffer bingkai, tekstur, atau output grafis lainnya).

Buat konteks yang ditangguhkan menggunakan ID3D11Device::CreateDeferredContext (bukan D3D11CreateDevice atau D3D11CreateDeviceAndSwapChain, yang membuat konteks langsung). Untuk informasi selengkapnya, lihat Penyajian Segera dan Ditangguhkan.