Interop Direct3D 12
D3D12 dapat digunakan untuk menulis aplikasi komponen.
Gambaran umum interop
D3D12 bisa sangat kuat, dan memungkinkan aplikasi untuk menulis kode grafis dengan efisiensi seperti konsol, tetapi tidak setiap aplikasi perlu menciptakan kembali roda dan menulis keseluruhan mesin rendering mereka dari awal. Dalam beberapa kasus, komponen atau pustaka lain telah melakukannya dengan lebih baik, atau dalam kasus lain, performa sebagian kode tidak sekritis kebenaran dan keterbacaannya.
Bagian ini mencakup teknik interop berikut:
- D3D12 dan D3D12, pada perangkat yang sama
- D3D12 dan D3D12, pada perangkat yang berbeda
- D3D12 dan kombinasi D3D11, D3D10, atau D2D, pada perangkat yang sama
- D3D12 dan kombinasi D3D11, D3D10, atau D2D, pada perangkat yang berbeda
- D3D12 dan GDI, atau D3D12 dan D3D11 dan GDI
Alasan untuk menggunakan interop
Ada beberapa alasan aplikasi menginginkan interop D3D12 dengan API lain. Beberapa contoh:
- Porting inkremental: ingin memindahkan seluruh aplikasi dari D3D10 atau D3D11 ke D3D12, sambil membuatnya berfungsi pada tahap menengah dari proses porting (untuk mengaktifkan pengujian dan penelusuran kesalahan).
- Kode kotak hitam: ingin membiarkan bagian tertentu dari aplikasi apa adanya saat memindahkan kode lainnya. Misalnya, mungkin tidak perlu port elemen UI dari sebuah game.
- Komponen yang tidak dapat diubah: perlu menggunakan komponen yang tidak dimiliki oleh aplikasi, yang tidak ditulis untuk menargetkan D3D12.
- Komponen baru: tidak ingin memindahkan seluruh aplikasi, tetapi ingin menggunakan komponen baru yang ditulis menggunakan D3D12.
Ada empat teknik utama untuk interop di D3D12:
- Aplikasi dapat memilih untuk menyediakan daftar perintah terbuka ke komponen, yang merekam beberapa perintah penyajian tambahan ke target render yang sudah terikat. Ini setara dengan menyediakan konteks perangkat yang disiapkan ke komponen lain di D3D11, dan sangat bagus untuk hal-hal seperti menambahkan UI/teks ke buffer back yang sudah terikat.
- Aplikasi dapat memilih untuk menyediakan antrean perintah ke komponen, bersama dengan sumber daya tujuan yang diinginkan. Ini setara dengan menggunakan CLEARState atau DeviceContextState API di D3D11 untuk menyediakan konteks perangkat yang bersih ke komponen lain. Ini adalah bagaimana komponen seperti D2D beroperasi.
- Komponen dapat memilih model di mana ia menghasilkan daftar perintah, berpotensi secara paralel, yang bertanggung jawab atas pengiriman aplikasi di lain waktu. Setidaknya satu sumber daya harus disediakan di seluruh batas komponen. Teknik yang sama ini tersedia di D3D11 menggunakan konteks yang ditangguhkan, meskipun performa di D3D12 lebih diinginkan.
- Setiap komponen memiliki antrean dan/atau perangkatnya sendiri, dan aplikasi dan komponen perlu berbagi sumber daya dan informasi sinkronisasi di seluruh batas komponen. Ini mirip dengan warisan
ISurfaceQueue
, dan IDXGIKeyedMutex yang lebih modern.
Perbedaan antara skenario ini adalah apa yang sebenarnya dibagikan antara batas komponen. Perangkat diasumsikan dibagikan, tetapi karena pada dasarnya stateless, perangkat tersebut tidak benar-benar relevan. Objek kunci adalah daftar perintah, antrean perintah, objek sinkronisasi, dan sumber daya. Masing-masing memiliki komplikasi mereka sendiri saat membagikannya.
Berbagi daftar perintah
Metode interop yang paling sederhana hanya memerlukan berbagi daftar perintah dengan sebagian mesin. Setelah operasi penyajian selesai, kepemilikan daftar perintah kembali ke pemanggil. Kepemilikan daftar perintah dapat dilacak melalui tumpukan. Karena daftar perintah adalah utas tunggal, tidak ada cara bagi aplikasi untuk melakukan sesuatu yang unik atau inovatif menggunakan teknik ini.
Berbagi antrean perintah
Mungkin teknik yang paling umum untuk beberapa komponen yang berbagi perangkat dalam proses yang sama.
Ketika antrean perintah adalah unit berbagi, perlu ada panggilan ke komponen untuk memberi tahu bahwa semua daftar perintah yang luar biasa perlu dikirimkan ke antrean perintah segera (dan antrean perintah internal apa pun perlu disinkronkan). Ini setara dengan API Flush D3D11, dan merupakan satu-satunya cara aplikasi dapat mengirimkan daftar perintahnya sendiri atau menyinkronkan primitif.
Berbagi primitif sinkronisasi
Pola yang diharapkan untuk komponen yang beroperasi pada perangkat dan/atau antrean perintahnya sendiri adalah menerima ID3D12Fence atau handel bersama, dan pasangan UINT64 setelah memulai pekerjaannya, yang akan ditunggu, dan kemudian ID3D12Fence kedua atau handel bersama, dan pasangan UINT64 yang akan memberi sinyal ketika semua pekerjaan selesai. Pola ini cocok dengan implementasi IDXGIKeyedMutex saat ini dan desain sinkronisasi model flip DWM/DXGI.
Berbagi sumber daya
Sejauh ini, bagian paling rumit dari penulisan aplikasi D3D12 yang memanfaatkan beberapa komponen adalah cara menangani sumber daya yang dibagikan di seluruh batas komponen. Hal ini sebagian besar disebabkan oleh konsep status sumber daya. Meskipun beberapa aspek desain status sumber daya dimaksudkan untuk menangani sinkronisasi intra-command-list, yang lain memang berdampak di antara daftar perintah, memengaruhi tata letak sumber daya dan kumpulan operasi yang valid atau karakteristik performa mengakses data sumber daya.
Ada dua pola menangani komplikasi ini, yang keduanya pada dasarnya melibatkan kontrak antar komponen.
- Kontrak dapat didefinisikan oleh pengembang komponen dan didokumenkan. Ini bisa sesingkat "sumber daya harus dalam status default ketika pekerjaan dimulai, dan akan dimasukkan kembali dalam status default ketika pekerjaan selesai" atau dapat memiliki aturan yang lebih rumit untuk memungkinkan hal-hal seperti berbagi buffer kedalaman tanpa memaksa penyelesaian kedalaman menengah.
- Kontrak dapat ditentukan oleh aplikasi pada waktu proses, pada saat sumber daya dibagikan di seluruh batas komponen. Ini terdiri dari dua informasi yang sama - status sumber daya akan berada di ketika komponen mulai menggunakannya, dan status komponen harus meninggalkannya ketika selesai.
Memilih model interop
Untuk sebagian besar aplikasi D3D12, berbagi antrean perintah mungkin merupakan model yang ideal. Ini memungkinkan kepemilikan lengkap pembuatan dan pengiriman kerja, tanpa overhead memori tambahan dari memiliki antrean redundan, dan tanpa dampak perf berurusan dengan primitif sinkronisasi GPU.
Berbagi primitif sinkronisasi diperlukan setelah komponen perlu menangani properti antrean yang berbeda, seperti jenis atau prioritas, atau setelah berbagi perlu menjangkau batas proses.
Berbagi atau menghasilkan daftar perintah tidak banyak digunakan secara eksternal oleh komponen pihak ketiga, tetapi mungkin banyak digunakan dalam komponen yang internal untuk mesin game.
API Interop
Topik Direct3D 11 on 12 memanjakan Anda melalui penggunaan sebagian besar permukaan API yang terkait dengan jenis interoperabilitas yang dijelaskan dalam topik ini.
Lihat juga metode ID3D12Device::CreateSharedHandle , yang dapat Anda gunakan untuk berbagi permukaan antara API grafis Windows.