Porting dari Direct3D 11 ke Direct3D 12
Bagian ini memberikan beberapa panduan tentang porting dari mesin grafis Direct3D 11 kustom ke Direct3D 12.
- Pembuatan perangkat
- Sumber daya berkomitmen
- Sumber daya yang dipesan
- Mengunggah data
- Shader dan objek shader
- Mengirimkan pekerjaan ke GPU
- Sinkronisasi CPU/GPU
- Pengikatan Sumber Daya
- Status sumber daya
- Swapchains
- Penyajian fungsi tetap
- Peluang dan akhir
- Topik terkait
Pembuatan perangkat
Direct3D 11 dan Direct3D 12 berbagi pola pembuatan perangkat serupa. Driver Direct3D 12 yang ada semuanya D3D_FEATURE_LEVEL_11_0 atau lebih baik, sehingga Anda dapat mengabaikan tingkat fitur yang lebih lama dan batasan terkait.
Perlu diingat juga bahwa dengan Direct3D 12, Anda harus secara eksplisit menghitung informasi perangkat menggunakan antarmuka DXGI. Di Direct3D 11, Anda dapat menautkan kembali ke perangkat DXGI dari perangkat Direct3D, dan ini tidak didukung untuk Direct3D 12.
Membuat perangkat lunak WARP di Direct3D 12 dilakukan dengan menyediakan adaptor eksplisit yang diperoleh dari IDXGIFactory4::EnumWarpAdapter. Perangkat WARP untuk Direct3D 12 hanya tersedia pada sistem dengan fitur opsional Alat Grafis diaktifkan.
Catatan
Tidak ada yang setara dengan D3D11CreateDeviceAndSwapChain. Bahkan dengan Direct3D 11, kami mencegah penggunaan fungsi ini karena sering lebih baik untuk membuat perangkat dan swapchain dalam langkah-langkah yang berbeda.
Sumber daya berkomitmen
Objek yang dibuat dengan antarmuka berikut di Direct3D 11, diterjemahkan ke apa yang disebut "sumber daya berkomitmen" di Direct3D 12. Sumber daya yang berkomitmen adalah sumber daya yang memiliki ruang alamat virtual dan halaman fisik yang terkait dengannya. Ini adalah konsep Model Memori Microsoft Windows Device Driver 2 (WDD2), di mana Direct3D 12 didasarkan.
Sumber daya Direct3D 11:
- ID3D11Resource
- ID3D11Buffer dan ID3D11Device::CreateBuffer
- ID3D11Texture1D dan ID3D11Device:CreateTexture1D
- ID3D11Texture2D dan ID3D11Device::CreateTexture2D
- ID3D11Texture3D dan ID3D11Device::CreateTexture3D
Di Direct3D 12, semuanya diwakili oleh ID3D12Resource dan ID3D12Device::CreateCommittedResource.
Sumber daya yang dipesan
Sumber daya yang dipesan adalah sumber daya di mana hanya ruang alamat virtual yang telah dialokasikan, memori fisik tidak dialokasikan sampai ada panggilan ke ID3D12Device::CreateHeap. Ini pada dasarnya adalah konsep yang sama dengan sumber daya ubin di Direct3D 11.
Bendera (D3D11_RESOURCE_MISC_FLAG) yang digunakan dalam Direct3D 11 untuk menyiapkan sumber daya berjenjang, lalu memetakannya ke memori fisik.
- D3D11_RESOURCE_MISC_TILED
- D3D11_RESOURCE_MISC_TILE_POOL
Mengunggah data
Di Direct3D 11 ada tampilan satu garis waktu (panggilan mengikuti urutan, seperti data yang diinisialisasi dengan D3D11_SUBRESOURCE_DATA, lalu panggilan dilakukan ke ID3D11DeviceContext::UpdateSubresource, lalu panggilan ke ID3D11DeviceContext::Map). Jumlah salinan yang dibuat dari data tidak jelas untuk pengembang Direct3D 11.
Di Direct3D 12 ada dua garis waktu, garis waktu GPU (disiapkan oleh panggilan ke CopyTextureRegion, dan CopyBufferRegion dari memori yang dapat dipetakan) dan garis waktu CPU (ditentukan oleh panggilan ke Peta). Fungsi pembantu disediakan (dalam file d3dx12.h) yang disebut Updatesubresources yang menggunakan garis waktu bersama. Ada beberapa variasi fungsi pembantu ini, yang menggunakan ID3D12Device::GetCopyableFootprints, yang lain yang menggunakan mekanisme alokasi tumpukan, dan yang lain yang menggunakan mekanisme alokasi tumpukan. Fungsi pembantu ini menyalin sumber daya ke GPU dan CPU, melalui area penahapan memori perantara.
Biasanya GPU dan CPU masing-masing memiliki salinan sumber daya mereka sendiri yang terkait dengan garis waktu mereka sendiri. Pendekatan garis waktu bersama juga mempertahankan dua salinan.
Shader dan objek shader
Dalam Direct3D 11 ada banyak pembuatan objek shader dan status, dan mengatur status objek tersebut, menggunakan metode pembuatan ID3D11Device dan metode set ID3D11DeviceContext. Biasanya sejumlah besar panggilan dilakukan ke metode ini, yang kemudian digabungkan pada waktu gambar oleh driver untuk mengatur status alur yang benar.
Di Direct3D 12 pengaturan status alur ini telah digabungkan ke dalam satu objek (CreateComputePipelineState untuk mesin komputasi, dan CreateGraphicsPipelineState untuk mesin grafis), yang kemudian dilampirkan ke daftar perintah sebelum panggilan gambar dengan panggilan ke SetPipelineState.
Panggilan ini menggantikan semua panggilan individual untuk mengatur shader, tata letak input, status campuran, status rasterizer, status stensil kedalaman, dan sebagainya, di Direct3D 11
- Metode perangkat 11:
CreateInputLayout
, ,CreateXShader
CreateDepthStencilState
, danCreateRasterizerState
. - Metode Konteks Perangkat 11:
IASetInputLayout
, ,xxSetShader
,OMSetBlendState
OMSetDepthStencilState
, danRSSetState
.
Meskipun Direct3D 12 dapat mendukung blob shader yang dikompilasi yang lebih lama, shader harus dibangun menggunakan Model Shader 5.1 dengan API FXC/D3DCompile, atau menggunakan Shader Model 6 menggunakan pengkompilasi DXIL DXC. Anda harus memvalidasi dukungan Shader Model 6 dengan CheckFeatureSupport dan D3D12_FEATURE_SHADER_MODEL.
Mengirimkan pekerjaan ke GPU
di Direct3D 11 ada sedikit kontrol atas sebenarnya bagaimana pekerjaan dikirimkan, sebagian besar ditangani oleh driver, meskipun beberapa kontrol diaktifkan melalui panggilan ID3D11DeviceContext::Flush dan IDXGISwapChain1::P resent1.
Dalam pengiriman kerja Direct3D 12 sangat eksplisit dan dikendalikan oleh aplikasi. Konstruksi utama untuk mengirimkan pekerjaan adalah ID3D12GraphicsCommandList, yang digunakan untuk merekam semua perintah aplikasi (dan cukup mirip dalam konsep dengan konteks yang ditangguhkan ID3D11). Penyimpanan cadangan untuk daftar perintah disediakan oleh ID3D12CommandAllocator, yang memungkinkan aplikasi mengelola pemanfaatan memori daftar perintah dengan benar-benar mengekspos memori yang akan digunakan driver Direct3D 12 untuk menyimpan daftar perintah.
Akhirnya ID3D12CommandQueue adalah antrean first-in first-out, yang menyimpan urutan yang benar dari daftar perintah untuk pengiriman ke GPU. Hanya ketika satu daftar perintah telah menyelesaikan eksekusi pada GPU, akankah daftar perintah berikutnya dari antrean dikirimkan oleh driver.
Di Direct3D 11 tidak ada konsep eksplisit dari antrean perintah. Dalam penyiapan umum untuk Direct3D 12, daftar perintah D3D12_COMMAND_LIST_TYPE_DIRECT yang saat ini terbuka untuk bingkai saat ini dapat dianggap analog dengan konteks langsung Direct3D 11. Ini menyediakan banyak fungsi yang sama.
D3D11DeviceContext | ID3D12GraphicsCommand List |
---|---|
ClearDepthStencilView | ClearDepthStencilView |
ClearRenderTargetView | ClearRenderTargetView |
ClearUnorderedAccess* | ClearUnorderedAccess* |
Gambar, DrawInstanced | DrawInstanced |
DrawIndexed, DrawIndexedInstanced | DrawIndexedInstanced |
Kirim | Kirim |
IASetInputLayout, xxSetShader, dll. | SetPipelineState |
OMSetBlendState | OMSetBlendFactor |
OMSetDepthStencilState | OMSetStencilRef |
OMSetRenderTargets | OMSetRenderTargets |
RSSetViewports | RSSetViewports |
RSSetScissorRects | RSSetScissorRects |
IASetPrimitiveTopology | IASetPrimitiveTopology |
IASetVertexBuffers | IASetVertexBuffers |
IASetIndexBuffer | IASetIndexBuffer |
ResolveSubresource | ResolveSubresource |
CopySubresourceRegion | CopyBufferRegion |
UpdateSubresource | CopyTextureRegion |
CopyResource | CopyResource |
Catatan
Daftar perintah yang dibuat dengan D3D12_COMMAND_LIST_TYPE_BUNDLE simliar ke konteks yang ditangguhkan. Direct3D 12 juga mendukung kemampuan untuk mengakses beberapa fitur konteks langsung secara bersamaan untuk dirender melalui jenis daftar perintah D3D12_COMMAND_LIST_TYPE_COPY dan D3D12_COMMAND_LIST_TYPE_COMPUTE .
Sinkronisasi CPU/GPU
Dalam sinkronisasi CPU/GPU Direct3D 11 sebagian besar otomatis, dan tidak perlu aplikasi mempertahankan status memori fisik.
di Direct3D 12 aplikasi harus mengelola dua garis waktu (CPU dan GPU) secara eksplisit. Ini mengharuskan informasi perlu dipertahankan, oleh aplikasi, tentang sumber daya apa yang diperlukan oleh GPU, dan untuk berapa lama. Ini juga berarti bahwa aplikasi bertanggung jawab untuk memastikan konten sumber daya (sumber daya yang diterapkan, timbunan, alokator perintah, misalnya) tidak berubah sampai GPU selesai menggunakannya.
Objek utama untuk menyinkronkan garis waktu adalah objek ID3D12Fence. Pengoperasian pagar cukup sederhana, mereka memungkinkan GPU untuk memberi sinyal ketika telah menyelesaikan tugas. GPU dan CPU dapat memberi sinyal, dan keduanya dapat menunggu di pagar.
Biasanya pendekatannya adalah bahwa ketika mengirimkan daftar perintah untuk eksekusi, sinyal pagar ditransmisikan oleh GPU saat selesai (ketika selesai membaca data), memungkinkan CPU untuk menggunakan kembali atau menghancurkan sumber daya.
Dalam Direct3D 11 , bendera ID3D11DeviceContext::Map D3D11_MAP_WRITE_DISCARD pada dasarnya memperlakukan setiap sumber daya sebagai pasokan memori tanpa akhir yang dapat ditulis aplikasi (proses yang dikenal sebagai "penggantian nama"). Di Direct3D 12 lagi prosesnya eksplisit: memori tambahan perlu dialokasikan, dan pagar harus digunakan untuk menyinkronkan operasi. Buffer cincin (terdiri dari buffer besar) mungkin merupakan teknik yang baik untuk ini, lihat skenario buffer cincin dalam Manajemen Sumber Daya Berbasis Pagar.
Pengikatan Sumber Daya
Tampilan di Direct3D 11 (tampilan sumber daya shader, tampilan target render, dan sebagainya), sebagian besar telah diganti di Direct3D 12 dengan konsep deskriptor. Metode pembuatan masih ada di Direct3D 12 (seperti CreateShaderResourceView dan CreateRenderTargetView), yang dipanggil setelah tumpukan deskriptor dibuat, untuk menulis data ke dalam tumpukan. Pengikatan di Direct3D 12 sekarang ditangani oleh handel deskriptor yang dijelaskan dalam tanda tangan root, dan dikirimkan menggunakan metode SetGraphicsRootDescriptorTable atau SetComputeRootDescriptorTable.
Tanda tangan akar merinci pemetaan antara nomor slot tanda tangan akar dan tabel deskriptor, di mana tabel deskriptor dapat berisi referensi ke sumber daya yang tersedia untuk shader vertex, shader piksel, dan shader lainnya, seperti buffer konstanta, tampilan sumber daya shader, dan sampler. Fleksibilitas ini memutuskan ruang register HLSL dari ruang pengikatan API di Direct3D 12, tidak seperti Direct3D 11 di mana ada pemetaan satu ke satu di antara ini.
Salah satu implikasi dari sistem ini adalah bahwa aplikasi bertanggung jawab untuk mengganti nama tabel deskriptor, yang memungkinkan pengembang untuk memahami biaya performa perubahan bahkan satu deskriptor per panggilan gambar.
Fitur baru Direct3D 12 adalah bahwa aplikasi dapat mengontrol deskriptor mana yang dibagikan di antara tahap shader mana. Dalam sumber daya Direct3D 11 seperti UAV dibagikan antara semua tahap shader. Dengan mengaktifkan deskriptor untuk dinonaktifkan untuk tahap shader tertentu, register yang digunakan oleh deskriptor yang telah dinonaktifkan tersedia untuk digunakan oleh deskriptor yang diaktifkan untuk tahap shader tertentu.
Tabel berikut ini memperlihatkan contoh tanda tangan akar.
Slot Parameter Akar | Entri Tabel Deskriptor |
---|---|
0 | Rentang Deskriptor VS b0-b13 |
1 | Rentang Deskriptor VS t0-t127 |
2 | Rentang Deskriptor VS s0-s16 |
3 | Rentang Deskriptor PS b0-b13 |
... | |
14 | Rentang Deskriptor DS s0-16 |
15 | Rentang Deskriptor Bersama u0-u63 |
Status sumber daya
Dalam status sumber daya Direct3D 11 tidak dikelola oleh aplikasi, tetapi oleh driver.
Dalam Direct3D 12 mempertahankan status sumber daya menjadi tanggung jawab aplikasi, untuk mengaktifkan paralelisme penuh dalam perekaman daftar perintah: aplikasi harus menangani garis waktu perekaman untuk daftar perintah (yang dapat dilakukan secara paralel), dan garis waktu eksekusi yang harus berurutan.
Transisi status sumber daya ditangani oleh metode ResourceBarrier. Terutama aplikasi harus menginformasikan driver saat penggunaan sumber daya berubah. Misalnya jika sumber daya digunakan sebagai target render, dan kemudian akan digunakan sebagai input ke shader vertex pada panggilan gambar berikutnya, maka ini mungkin memerlukan kios pendek dalam operasi GPU untuk menyelesaikan operasi target render sebelum menangani shader vertex.
Sistem ini memungkinkan sinkronisasi biji-bijian halus (kios GPU) dari alur grafis, serta cache flush dan mungkin beberapa perubahan tata letak memori (seperti merender tampilan target ke dekompresi tampilan stensil kedalaman).
Ini dikenal sebagai hambatan transisi. Ada jenis hambatan lain, di Direct3D 11 ID3D11DeviceContext2::TiledResourceBarrier mengaktifkan memori fisik yang sama untuk digunakan oleh dua sumber daya berjenjang yang berbeda. Dalam Direct3D 12, ini disebut sebagai "hambatan alias". Hambatan alias dapat digunakan untuk sumber daya ubin dan ditempatkan di Direct3D 12. Selain itu ada hambatan UAV. Dalam Direct3D 11 semua pengiriman UAV dan operasi gambar diperlukan untuk diserialisasikan, meskipun operasi ini dapat disalurkan atau bekerja secara paralel. Untuk Direct3D 12, pembatasan ini dihapus oleh penambahan penghalang UAV. Hambatan UAV memastikan bahwa operasi UAV berurutan, jadi jika operasi kedua mengharuskan operasi pertama selesai, yang kedua akan dipaksa untuk menunggu dengan penambahan hambatan. Operasi default untuk UAV hanyalah operasi akan dilanjutkan secepat mungkin.
Jelas ada keuntungan performa jika beban kerja dapat diparalelkan.
Swapchains
Rantai pertukaran DXGI adalah dasar untuk rantai pertukaran di Direct3D 11 dan 12. Ada beberapa perbedaan kecil, dalam Direct3D 11 ketiga jenis rantai pertukaran adalah SEQUENTIAL, DISCARD, dan FLIP_SEQUENTIAL. Untuk Direct3D 12 hanya ada dua jenis: FLIP_SEQUENTIAL dan FLIP_DISCARD. Seperti disebutkan di atas, Anda harus secara eksplisit membuat swapchain Anda melalui IDXGIFactory4, atau yang lebih baru, dan menggunakan antarmuka yang sama untuk enumerasi adaptor apa pun.
Di Direct3D 11 ada rotasi backbuffer otomatis: hanya satu tampilan target render yang diperlukan untuk buffer belakang 0. Dalam rotasi buffer Direct3D 12 bersifat eksplisit, perlu ada tampilan target render untuk setiap buffer belakang. Gunakan metode IDXGISwapChain3::GetCurrentBackBufferIndex untuk memilih metode yang akan dirender. Sekali lagi fleksibilitas tambahan ini memungkinkan paralelisasi yang lebih besar.
Catatan
Meskipun ada banyak cara untuk menyiapkan aplikasi Anda, umumnya aplikasi memiliki satu ID3D12CommandAllocator per buffer swap-chain. Ini memungkinkan aplikasi untuk melanjutkan membangun sekumpulan perintah untuk bingkai berikutnya sementara GPU merender sebelumnya.
Penyajian fungsi tetap
Di Direct3D 11 ada beberapa metode yang menyederhanakan berbagai operasi tingkat yang lebih tinggi, seperti GenerateMips (membuat rantai mip penuh) dan DrawAuto (menggunakan output aliran sebagai input shader tanpa input lebih lanjut dari aplikasi). Metode ini tidak tersedia di Direct3D 12, aplikasi perlu menangani operasi ini dengan membuat shader untuk melakukannya.
Peluang dan akhir
Tabel berikut ini memperlihatkan sejumlah fitur yang mirip antara Direct3D 11 dan 12, tetapi tidak identik.
Direct3D 11 | Direct3D 12 |
---|---|
ID3D11Query | ID3D12QueryHeap memungkinkan kueri dikelompokkan bersama-sama, mengurangi biaya. |
ID3D11Predicate | Predikasi sekarang diaktifkan dengan memiliki data dalam buffer yang sepenuhnya transparan. Objek Direct3D 11 ID3D11Predicate digantikan oleh ID3D12Resource::Map, yang harus mengikuti panggilan ke ResolveQueryData dan operasi sinkronisasi GPU menggunakan pagar untuk menunggu data siap. Lihat Predikasi. |
Penghitung tersembunyi UAV/SO | Aplikasi ini bertanggung jawab atas alokasi dan manajemen penghitung SO/UAV. Lihat Penghitung Output Aliran dan Penghitung UAV. |
MinLOD dinamis sumber daya (tingkat detail minium) | Ini telah dipindahkan ke MinLOD statis deskriptor SRV. |
Draw*Indirect/DispatchIndirect | Menggambar metode tidak langsung semuanya digabungkan ke dalam satu metode ExecuteIndirect. |
Format DepthStencil saling terkait | Format DepthStencil adalah planar. Misalnya format kedalaman 24 bit, 8 bit stensil akan disimpan dalam format 24/8/24/8... dll di Direct3D 11, tetapi sebagai 24/ 24 / 24 ... diikuti oleh 8/8/8... di Direct3D 12. Perhatikan bahwa setiap bidang adalah sub-sumber dayanya sendiri di D3D12 (lihat Subresources). |
ResizeTilePool | Sumber daya yang dipesan dapat dipetakan ke beberapa timbunan. Ketika kumpulan petak peta akan ditanam di D3D11, timbunan tambahan dapat dialokasikan di D3D12 sebagai gantinya. |