Bagikan melalui


Membuat Tanda Tangan Akar

Tanda tangan akar adalah struktur data kompleks yang berisi struktur berlapis. Ini dapat ditentukan 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 tanda tangan akar mengambil versi serial (mandiri, bebas pointer) dari deskripsi tata letak yang dijelaskan di bawah ini. Metode disediakan untuk menghasilkan versi berseri 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 tanda tangan akar, lihat Tanda Tangan Akar Versi 1.1

Tipe Ikatan 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 dari jenis tertentu (seperti SRV) dalam tabel deskriptor.

D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND Makro biasanya dapat digunakan untuk OffsetInDescriptorsFromTableStart parameter D3D12_DESCRIPTOR_RANGE. Ini berarti menambahkan rentang deskriptor yang ditentukan setelah yang sebelumnya dalam tabel deskriptor. Jika aplikasi ingin alias deskriptor atau karena alasan tertentu ingin melewati slot, aplikasi dapat mengatur OffsetInDescriptorsFromTableStart ke offset apa pun yang diinginkan. Menentukan rentang tumpang tindih dari berbagai jenis tidak valid.

Kumpulan daftar shader yang ditentukan oleh kombinasi RangeType, , NumDescriptors, BaseShaderRegisterdan RegisterSpace tidak dapat bertentangan atau tumpang tindih di deklarasi apa pun dalam tanda tangan akar 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) sebaris dalam tanda tangan akar.

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.

Visibilitas Shader

Anggota enum D3D12_SHADER_VISIBILITY diatur ke dalam parameter visibilitas shader D3D12_ROOT_PARAMETER menentukan shader mana yang melihat konten slot tanda tangan akar tertentu. Komputasi selalu menggunakan _ALL (karena hanya ada satu tahap aktif). Grafik dapat memilih, tetapi jika menggunakan _ALL, semua tahap shader melihat apa pun yang terikat di slot tanda tangan akar.

Salah satu penggunaan visibilitas shader adalah untuk membantu shader yang ditulis mengharapkan pengikatan yang berbeda per tahap shader menggunakan namespace layanan 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 mendefinisikan benar-benar ingin setiap shader melihat tekstur yang berbeda, shader dapat menentukan 2 slot tanda tangan root dengan VISIBILITY_VERTEX dan _PIXEL. Tidak peduli apa visibilitasnya pada slot tanda tangan akar, ia selalu memiliki biaya yang sama (biaya hanya tergantung pada apa SlotType) terhadap satu ukuran tanda tangan akar maksimum tetap.

Pada perangkat keras D3D11 low end, SHADER_VISIBILITY juga diperkirakan digunakan saat memvalidasi ukuran tabel deskriptor dalam tata letak root, 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 (register binding 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 D3D12_ROOT_PARAMETER_TYPE enum.

Untuk memulai slot tanda tangan root, lihat metode SetComputeRoot*** dan SetGraphicsRoot*** dari ID3D12GraphicsCommandList.

Sampel statis dijelaskan dalam tanda tangan 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 akar. 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 prokursif menghasilkan struktur data D3D12_ROOT_SIGNATURE_DESC , aplikasi harus membuat formulir berseri menggunakan D3D12SerializeRootSignature. Output yang dapat diteruskan ke ID3D12Device::CreateRootSignature.

Jika aplikasi sudah memiliki tanda tangan akar berseri, atau memiliki shader terkompilasi yang berisi tanda tangan akar dan ingin secara terprogram menemukan definisi tata letak (dikenal sebagai "refleksi"), D3D12CreateRootSignatureDeserializer dapat dipanggil. Ini menghasilkan antarmuka ID3D12RootSignatureDeserializer, yang berisi metode untuk mengembalikan struktur data D3D12_ROOT_SIGNATURE_DESC yang dideserialisasi. Antarmuka memiliki masa pakai struktur data yang dideserialisasi.

API Pembuatan Tanda Tangan Akar

ID3D12Device::CreateRootSignature API mengambil versi serial tanda tangan root.

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 mengambil alih tanda tangan akar apa pun yang sudah ada di shader.

Jika tanda tangan akar diteruskan ke salah satu metode status buat alur, tanda tangan akar ini divalidasi terhadap semua shader di PSO untuk kompatibilitas dan diberikan kepada driver untuk digunakan dengan 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 tanda tangan akar tidak diteruskan, semua shader yang diteruskan harus memiliki tanda tangan akar dan harus 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 waktu draw(graphics)/dispatch(compute) dipanggil, aplikasi harus memastikan bahwa PSO saat ini cocok dengan tanda tangan akar saat ini; jika tidak, perilaku tidak ditentukan.

Kode untuk Menentukan Tanda Tangan Akar Versi 1.1

Contoh di bawah ini menunjukkan cara membuat tanda tangan akar dengan format berikut:

RootParameterIndex Konten 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 } (unbounded # dari SRV, deskriptor volatil)
[5] Tabel deskriptor: { (t0, space1) - unbounded } (unbounded # dari SRV, deskriptor volatil)
[6] Tabel deskriptor: { b1 } (1 CBV, data statis)

 

Jika sebagian besar bagian dari tanda tangan akar digunakan sebagian besar waktu itu bisa lebih baik daripada harus mengganti 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 tanda tangan akar, driver mungkin harus membuat salinan beberapa atau semua status tanda tangan akar, yang dapat menjadi biaya nontrivial ketika dikalikan di banyak perubahan status.

Selain itu, tanda tangan 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(...);
}

Tanda Tangan Akar

Menentukan Tanda Tangan Akar di HLSL

Menggunakan Tanda Tangan Akar