Membuat Root Signature
Tanda tangan akar adalah struktur data kompleks yang berisi struktur berlapis. Ini dapat didefinisikan secara terprogram menggunakan definisi struktur data di bawah ini (yang mencakup metode untuk membantu menginisialisasi anggota). Atau, mereka dapat ditulis dalam High Level Shading Language (HLSL) - memberikan keuntungan bahwa kompilator akan memvalidasi lebih awal bahwa tata letak kompatibel dengan shader.
API untuk membuat root signature memerlukan versi serial (mandiri, tanpa pointer) dari deskripsi tata letak yang dijelaskan di bawah ini. Metode disediakan untuk menghasilkan versi serial ini dari struktur data C++, tetapi cara lain untuk mendapatkan definisi tanda tangan akar berseri adalah dengan mengambilnya dari shader yang telah dikompilasi dengan tanda tangan akar.
Jika Anda ingin memanfaatkan pengoptimalan driver untuk deskriptor dan data root signature, lihat Root Signature Versi 1.1
- Jenis Pengikatan Tabel Deskriptor
- Rentang Deskriptor
- Tata Letak Tabel Deskriptor
- Konstanta Akar
- Deskriptor Akar
- Visibilitas Shader
- Definisi Tanda Tangan Akar
- Serialisasi/Deserialisasi Struktur Data Tanda Tangan Akar
- API Pembuatan Tanda Tangan Akar
- Tanda Tangan Akar dalam Objek Status Alur
- Kode untuk Mendefinisikan Tanda Tangan Akar Versi 1.1
- Topik terkait
Jenis Pengikatan Tabel Deskriptor
enum D3D12_DESCRIPTOR_RANGE_TYPE menentukan jenis deskriptor yang dapat direferensikan sebagai bagian dari definisi tata letak tabel deskriptor.
Ini adalah rentang sehingga, misalnya jika bagian dari tabel deskriptor memiliki 100 SRV, rentang tersebut dapat dideklarasikan dalam satu entri daripada 100. Jadi definisi tabel deskriptor adalah kumpulan rentang.
typedef enum D3D12_DESCRIPTOR_RANGE_TYPE
{
D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER
} D3D12_DESCRIPTOR_RANGE_TYPE;
Rentang Deskriptor
Struktur D3D12_DESCRIPTOR_RANGE mendefinisikan rentang deskriptor jenis tertentu (seperti SRV) dalam tabel deskriptor.
Makro D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND
biasanya dapat digunakan untuk parameter OffsetInDescriptorsFromTableStart
D3D12_DESCRIPTOR_RANGE. Ini berarti menambahkan rentang deskriptor yang ditentukan setelah yang sebelumnya dalam tabel deskriptor. Jika aplikasi ingin mengubah nama deskriptor atau karena alasan tertentu ingin melewati slot, dapat mengatur OffsetInDescriptorsFromTableStart
ke offset apa pun yang diinginkan. Menentukan rentang yang saling tumpang tindih dari tipe yang berbeda tidak valid.
Kumpulan register shader yang ditentukan oleh kombinasi RangeType
, NumDescriptors
, BaseShaderRegister
, dan RegisterSpace
tidak dapat bertentangan atau tumpang tindih di setiap deklarasi dalam root signature yang memiliki D3D12_SHADER_VISIBILITY umum (lihat bagian visibilitas shader di bawah).
Tata Letak Tabel Deskriptor
Struktur D3D12_ROOT_DESCRIPTOR_TABLE mendeklarasikan tata letak tabel deskriptor sebagai kumpulan rentang deskriptor yang dimulai pada offset tertentu dari timbunan deskriptor. Sampler tidak diizinkan dalam tabel deskriptor yang sama dengan CBV/UAV/SRV.
Struktur ini digunakan ketika jenis slot tanda tangan akar diatur ke D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE
.
Untuk mengatur tabel deskriptor grafis (CBV, SRV, UAV, Sampler), gunakan ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable.
Untuk mengatur tabel deskriptor komputasi, gunakan ID3D12GraphicsCommandList::SetComputeRootDescriptorTable.
Konstanta Akar
Struktur D3D12_ROOT_CONSTANTS mendeklarasikan konstanta sebaris dalam tanda tangan akar yang muncul dalam shader sebagai satu buffer konstanta.
Struktur ini digunakan ketika jenis slot tanda tangan akar diatur ke D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS
.
Deskriptor Akar
Struktur D3D12_ROOT_DESCRIPTOR mendeklarasikan deskriptor (yang muncul dalam shader) secara langsung dalam root signature.
Struktur ini digunakan ketika jenis slot tanda tangan akar diatur ke D3D12_ROOT_PARAMETER_TYPE_CBV
, D3D12_ROOT_PARAMETER_TYPE_SRV
atau D3D12_ROOT_PARAMETER_TYPE_UAV
.
Keterlihatan Shader
Anggota enum D3D12_SHADER_VISIBILITY yang diatur dalam parameter visibilitas shader dari D3D12_ROOT_PARAMETER menentukan shader mana yang dapat melihat konten dari slot tanda tangan akar tertentu. Komputasi selalu menggunakan _ALL (karena hanya ada satu tahap aktif). Grafik dapat memilih opsi, tetapi jika menggunakan _ALL, semua tahap pemrosesan shader mengakses semua yang terikat di slot tanda tangan akar.
Salah satu penggunaan visibilitas shader adalah untuk membantu shader yang dirancang dengan harapan pengikatan yang berbeda pada setiap tahap shader menggunakan namespace yang tumpang tindih. Misalnya, shader vertex dapat mendeklarasikan:
Texture2D foo : register(t0);
dan shader piksel juga dapat mendeklarasikan:
Texture2D bar : register(t0);
Jika aplikasi membuat pengikatan tanda tangan akar ke t0 VISIBILITY_ALL, kedua shader akan melihat tekstur yang sama. Jika shader ingin setiap shader melihat tekstur yang berbeda, shader tersebut dapat mendefinisikan 2 slot signature akar dengan VISIBILITY_VERTEX dan _PIXEL. Tidak peduli apa pun visibilitasnya pada slot tanda tangan akar, biaya selalu sama (hanya tergantung pada jenis SlotType) terhadap ukuran maksimum yang tetap dari tanda tangan akar.
Pada perangkat keras D3D11 low end, SHADER_VISIBILITY juga diperhitungkan digunakan saat memvalidasi ukuran tabel deskriptor dalam tata letak akar, karena beberapa perangkat keras D3D11 hanya dapat mendukung jumlah maksimum pengikatan per tahap. Pembatasan ini hanya diberlakukan saat berjalan pada perangkat keras tingkat rendah dan tidak membatasi perangkat keras yang lebih modern sama sekali.
Jika tanda tangan akar memiliki beberapa tabel deskriptor yang ditentukan yang saling tumpang tindih di namespace (pengikatan register ke shader) dan salah satunya menentukan _ALL untuk visibilitas, tata letak tidak valid (pembuatan akan gagal).
Definisi Tanda Tangan Akar
Struktur D3D12_ROOT_SIGNATURE_DESC dapat berisi tabel deskriptor dan konstanta sebaris, setiap jenis slot yang ditentukan oleh struktur D3D12_ROOT_PARAMETER dan enum D3D12_ROOT_PARAMETER_TYPE.
Untuk memulai slot tanda tangan root, lihat metode SetComputeRoot***, SetGraphicsRoot***, dan ID3D12GraphicsCommandList.
Sampel statis dijelaskan dalam signature akar menggunakan struktur D3D12_STATIC_SAMPLER.
Sejumlah bendera membatasi akses shader tertentu ke tanda tangan akar, lihat D3D12_ROOT_SIGNATURE_FLAGS.
Serialisasi / Deserialisasi Struktur Data Tanda Tangan Akar
Metode yang dijelaskan di bagian ini diekspor oleh D3D12Core.dll dan menyediakan metode untuk menserialisasikan dan mendeserialisasi struktur data tanda tangan akar.
Formulir berseri adalah apa yang diteruskan ke API saat membuat tanda tangan root. Jika shader telah ditulis dengan tanda tangan akar di dalamnya (ketika kemampuan tersebut ditambahkan), shader yang dikompilasi akan berisi tanda tangan akar berseri di dalamnya.
Jika aplikasi secara procedurural menghasilkan struktur data D3D12_ROOT_SIGNATURE_DESC, aplikasi harus membuat formulir berseri menggunakan D3D12SerializeRootSignature. Output dari itu dapat diteruskan ke ID3D12Device::CreateRootSignature.
Jika aplikasi sudah memiliki tanda tangan akar berseri, atau memiliki shader yang dikompilasi yang berisi tanda tangan akar dan ingin menemukan definisi tata letak secara terprogram (dikenal sebagai "refleksi"), D3D12CreateRootSignatureDeserializer dapat dipanggil. Ini menghasilkan antarmuka ID3D12RootSignatureDeserializer , yang berisi metode untuk mengembalikan struktur data D3D12_ROOT_SIGNATURE_DESC yang telah dideserialisasi. Antarmuka memiliki masa pakai struktur data yang dideserialisasi.
API Pembuatan Tanda Tangan Root
ID3D12Device::CreateRootSignature API menerima versi serial dari root signature.
Tanda Tangan Akar dalam Objek Status Alur
Metode untuk membuat status alur (ID3D12Device::CreateGraphicsPipelineState dan ID3D12Device::CreateComputePipelineState ) mengambil antarmuka ID3D12RootSignature opsional sebagai parameter input (disimpan dalam struktur D3D12_GRAPHICS_PIPELINE_STATE_DESC). Ini akan menggantikan root signature apa pun yang sudah ada pada shader.
Jika root signature diteruskan ke salah satu metode pembuatan status jalur, root signature ini divalidasi kompatibilitasnya dengan semua shader di dalam PSO dan diserahkan kepada driver untuk digunakan bersama semua shader. Jika salah satu shader memiliki tanda tangan akar yang berbeda di dalamnya, itu akan digantikan oleh tanda tangan akar yang diteruskan di API. Jika root signature tidak diteruskan, semua shader yang diteruskan harus memiliki root signature dan harus saling cocok - ini akan diberikan kepada driver. Mengatur PSO pada daftar perintah atau bundel tidak mengubah tanda tangan akar. Itu dicapai dengan metode SetGraphicsRootSignature dan SetComputeRootSignature. Pada saat draw(graphics)/dispatch(compute) dipanggil, aplikasi harus memastikan secara pasti bahwa PSO saat ini sesuai dengan root signature saat ini; jika tidak, perilaku menjadi tidak terdefinisi.
Kode untuk Menentukan Tanda Tangan Akar Versi 1.1
Contoh di bawah ini menunjukkan cara membuat tanda tangan root dengan format berikut:
RootParameterIndex | Isi | Nilai |
---|---|---|
[0] | Konstanta akar: { b2 } | (1 CBV) |
[1] | Tabel deskriptor: { t2-t7, u0-u3 } | (6 SRV + 4 UAV) |
[2] | CBV Akar: { b0 } | (1 CBV, data statis) |
[3] | Tabel deskriptor: { s0-s1 } | (2 Sampler) |
[4] | Tabel deskriptor: { t8 - unbounded } | (jumlah SRV tidak terbatas, deskriptor berubah-ubah) |
[5] | Tabel deskriptor: { (t0, spasi1) - tidak terbatas } | (jumlah tak terbatas dari SRV, deskriptor yang mudah berubah) |
[6] | Tabel deskriptor: { b1 } | (1 CBV, data statis) |
Jika sebagian besar bagian dari tanda tangan akar sering digunakan, itu bisa lebih baik daripada harus mengalihkan tanda tangan akar terlalu sering. Aplikasi harus mengurutkan entri dalam tanda tangan akar dari yang paling sering berubah menjadi paling sedikit. Ketika aplikasi mengubah pengikatan ke bagian mana pun dari signature root, driver mungkin harus membuat salinan beberapa atau semua status signature root, yang dapat menjadi biaya yang tidak sepele ketika dikalikan pada banyak perubahan status.
Selain itu, signature akar akan menentukan sampler statis yang melakukan pemfilteran tekstur anisotropik di shader register s3.
Setelah tanda tangan akar ini terikat, tabel deskriptor, CBV akar dan konstanta dapat ditetapkan ke ruang parameter [0..6]. misalnya tabel deskriptor (rentang dalam timbunan deskriptor) dapat terikat pada setiap parameter akar [1] dan [3..6].
CD3DX12_DESCRIPTOR_RANGE1 DescRange[6];
DescRange[0].Init(D3D12_DESCRIPTOR_RANGE_SRV,6,2); // t2-t7
DescRange[1].Init(D3D12_DESCRIPTOR_RANGE_UAV,4,0); // u0-u3
DescRange[2].Init(D3D12_DESCRIPTOR_RANGE_SAMPLER,2,0); // s0-s1
DescRange[3].Init(D3D12_DESCRIPTOR_RANGE_SRV,-1,8, 0,
D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE); // t8-unbounded
DescRange[4].Init(D3D12_DESCRIPTOR_RANGE_SRV,-1,0,1,
D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE);
// (t0,space1)-unbounded
DescRange[5].Init(D3D12_DESCRIPTOR_RANGE_CBV,1,1,
D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); // b1
CD3DX12_ROOT_PARAMETER1 RP[7];
RP[0].InitAsConstants(3,2); // 3 constants at b2
RP[1].InitAsDescriptorTable(2,&DescRange[0]); // 2 ranges t2-t7 and u0-u3
RP[2].InitAsConstantBufferView(0, 0,
D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC); // b0
RP[3].InitAsDescriptorTable(1,&DescRange[2]); // s0-s1
RP[4].InitAsDescriptorTable(1,&DescRange[3]); // t8-unbounded
RP[5].InitAsDescriptorTable(1,&DescRange[4]); // (t0,space1)-unbounded
RP[6].InitAsDescriptorTable(1,&DescRange[5]); // b1
CD3DX12_STATIC_SAMPLER StaticSamplers[1];
StaticSamplers[0].Init(3, D3D12_FILTER_ANISOTROPIC); // s3
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC RootSig(7,RP,1,StaticSamplers);
ID3DBlob* pSerializedRootSig;
CheckHR(D3D12SerializeVersionedRootSignature(&RootSig,pSerializedRootSig));
ID3D12RootSignature* pRootSignature;
hr = CheckHR(pDevice->CreateRootSignature(
pSerializedRootSig->GetBufferPointer(),pSerializedRootSig->GetBufferSize(),
__uuidof(ID3D12RootSignature),
&pRootSignature));
Kode berikut menggambarkan bagaimana tanda tangan akar di atas dapat digunakan pada daftar perintah grafis.
InitializeMyDescriptorHeapContentsAheadOfTime(); // for simplicity of the
// example
CreatePipelineStatesAhreadOfTime(pRootSignature); // The root signature is passed into
// shader / pipeline state creation
...
ID3D12DescriptorHeap* pHeaps[2] = {pCommonHeap, pSamplerHeap};
pGraphicsCommandList->SetDescriptorHeaps(2,pHeaps);
pGraphicsCommandList->SetGraphicsRootSignature(pRootSignature);
pGraphicsCommandList->SetGraphicsRootDescriptorTable(
6,heapOffsetForMoreData,DescRange[5].NumDescriptors);
pGraphicsCommandList->SetGraphicsRootDescriptorTable(5,heapOffsetForMisc,5000);
pGraphicsCommandList->SetGraphicsRootDescriptorTable(4,heapOffsetForTerrain,20000);
pGraphicsCommandList->SetGraphicsRootDescriptorTable(
3,heapOffsetForSamplers,DescRange[2].NumDescriptors);
pGraphicsCommandList->SetComputeRootConstantBufferView(2,pDynamicCBHeap,&CBVDesc);
MY_PER_DRAW_STUFF stuff;
InitMyPerDrawStuff(&stuff);
pGraphicsCommandList->SetGraphicsRoot32BitConstants(
0,RTSlot[0].Constants.Num32BitValues,&stuff,0);
SetMyRTVAndOtherMiscBindings();
for(UINT i = 0; i < numObjects; i++)
{
pGraphicsCommandList->SetPipelineState(PSO[i]);
pGraphicsCommandList->SetGraphicsRootDescriptorTable(
1,heapOffsetForFooAndBar[i],DescRange[1].NumDescriptors);
pGraphicsCommandList->SetGraphicsRoot32BitConstant(0,i,drawIDOffset);
SetMyIndexBuffers(i);
pGraphicsCommandList->DrawIndexedInstanced(...);
}
Topik terkait
-
Menggunakan Tanda Tangan Akar