共用方式為


建立根簽章

根簽章是包含巢狀結構的複雜資料結構。 您可以使用下列資料結構定義,以程式設計方式定義這些 (,其中包括協助初始化成員的方法) 。 或者,它們可以以高階網底語言 (HLSL) 撰寫–提供編譯器會提早驗證配置與著色器相容的優點。

用來建立根簽章的 API 會採用序列化 (獨立、無指標) 版本的版面配置描述,如下所述。 方法可用來從 C++ 資料結構產生這個序列化版本,但取得序列化根簽章定義的另一種方式是從已使用根簽章編譯的著色器擷取它。

如果您想要利用根簽章描述元和資料驅動程式優化,請參閱 根簽章 1.1 版

描述項資料表系結類型

列舉 D3D12_DESCRIPTOR_RANGE_TYPE 定義描述項的類型,這些描述項可做為描述項資料表配置定義的一部分參考。

這是一個範圍,例如,如果描述項資料表的一部分有 100 個 SRV,該範圍可以在一個專案中宣告,而不是 100。 因此描述項資料表定義是範圍的集合。

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;

描述項範圍

D3D12_DESCRIPTOR_RANGE結構會定義指定型別 (的描述項範圍,例如描述中繼資料表內的 SRV) 。

D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND宏通常可用於 OffsetInDescriptorsFromTableStartD3D12_DESCRIPTOR_RANGE的 參數。 這表示附加描述項資料表中前一個描述項之後所定義的描述項範圍。 如果應用程式想要別名描述元,或基於某些原因而想要略過位置,它可以設定 OffsetInDescriptorsFromTableStart 為所需的任何位移。 定義不同類型重迭的範圍無效。

NumDescriptorsBaseShaderRegisterRegisterSpace 的組合 RangeType 所指定的著色器暫存器集合,無法在根簽章中具有通用D3D12_SHADER_VISIBILITY (的任何宣告之間衝突或重迭, (請參閱下方的著色器可見度一節) 。

描述項表格配置

D3D12_ROOT_DESCRIPTOR_TABLE結構會將描述中繼資料表的配置宣告為描述項範圍的集合,從描述元堆積的指定位移開始。 在與 CBV/UAV/SRV 相同的描述中繼資料表中,不允許取樣器。

當根簽章位置類型設定為 D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE 時,會使用此結構。

若要設定 CBV、SRV、UAV、Sampler) 描述中繼資料表 (圖形,請使用 ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable

若要設定計算描述中繼資料表,請使用 ID3D12GraphicsCommandList::SetComputeRootDescriptorTable

根常數

D3D12_ROOT_CONSTANTS結構會在著色器中顯示為一個常數緩衝區的根簽章中,內嵌宣告常數。

當根簽章位置類型設定為 D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS 時,會使用此結構。

根描述項

D3D12_ROOT_DESCRIPTOR結構會宣告 (描述項,這些描述項會出現在著色器中,) 內嵌在根簽章中。

當根簽章位置類型設定為 D3D12_ROOT_PARAMETER_TYPE_CBVD3D12_ROOT_PARAMETER_TYPE_SRVD3D12_ROOT_PARAMETER_TYPE_UAV 時,會使用此結構。

著色器可見度

D3D12_SHADER_VISIBILITY列舉的成員設定為D3D12_ROOT_PARAMETER的著色器可見度參數會決定哪些著色器會看到指定根簽章位置的內容。 計算一律會使用_ALL (,因為只有一個作用中的階段) 。 圖形可以選擇,但如果使用_ALL,所有著色器階段都會看到根簽章位置上系結的任何專案。

著色器可見度的其中一個用法是協助撰寫的著色器,其預期每個著色器階段使用重迭命名空間的不同系結。 例如,頂點著色器可能會宣告:

Texture2D foo : register(t0);

和圖元著色器也可以宣告:

Texture2D bar : register(t0);

如果應用程式將根簽章系結至 t0 VISIBILITY_ALL,這兩個著色器都會看到相同的紋理。 如果著色器實際上想要讓每個著色器查看不同的紋理,則可以使用VISIBILITY_VERTEX和_PIXEL定義 2 個根簽章位置。 不論根簽章位置上的可見度為何,它一律會有相同的成本 (成本,取決於 SlotType) 到一個固定根簽章大小上限。

在低端 D3D11 硬體上,驗證根配置中的描述中繼資料表大小時,也會考慮SHADER_VISIBILITY,因為某些 D3D11 硬體只能支援每個階段的最大系結數量。 只有在低層硬體上執行,且完全不會限制更多新式硬體時,才會強制執行這些限制。

如果根簽章已定義多個描述項資料表,這些描述中繼資料表在命名空間中會彼此重迭, (著色器系結至著色器) ,且其中任一個都指定了可見度_ALL,則配置無效, (建立將會失敗) 。

根簽章定義

D3D12_ROOT_SIGNATURE_DESC結構可以包含描述項資料表和內嵌常數、由D3D12_ROOT_PARAMETER結構和列舉D3D12_ROOT_PARAMETER_TYPE定義的每個位置類型。

若要起始根簽章位置,請參閱ID3D12GraphicsCommandListSetComputeRoot**SetGraphicsRoot。

靜態取樣器會在根簽章中使用 D3D12_STATIC_SAMPLER 結構來描述。

許多旗標會限制特定著色器存取根簽章,請參閱 D3D12_ROOT_SIGNATURE_FLAGS

根簽章資料結構序列化/還原序列化

本節所述的方法會由D3D12Core.dll匯出,並提供序列化和還原序列化根簽章資料結構的方法。

序列化表單是在建立根簽章時傳遞至 API 的內容。 如果在新增) 新增該功能時,著色器已在其中撰寫根簽章, (,則編譯的著色器將會包含序列化的根簽章。

如果應用程式以程式方式產生 D3D12_ROOT_SIGNATURE_DESC 資料結構,則必須使用 D3D12SerializeRootSignature建立序列化表單。 的輸出可以傳遞至 ID3D12Device::CreateRootSignature

如果應用程式已經有序列化的根簽章,或具有包含根簽章的已編譯著色器,而且想要以程式設計方式探索 (稱為「反映」) 的配置定義,則可以呼叫 D3D12CreateRootSignatureDeserializer 。 這會產生 ID3D12RootSignatureDeserializer 介面,其中包含傳回還原序列化 D3D12_ROOT_SIGNATURE_DESC 資料結構的方法。 介面擁有還原序列化資料結構的存留期。

根簽章建立 API

ID3D12Device::CreateRootSignature API 會採用根簽章的序列化版本。

管線狀態物件中的根簽章

建立管線狀態的方法 (ID3D12Device::CreateGraphicsPipelineStateID3D12Device::CreateComputePipelineState ) 採用選擇性的 ID3D12RootSignature 介面作為儲存在 D3D12_GRAPHICS_PIPELINE_STATE_DESC結構) 中的輸入 (參數。 這會覆寫著色器中已存在的任何根簽章。

如果根簽章傳遞至其中一個建立管線狀態方法,此根簽章會針對 PSO 中的所有著色器進行驗證,以供驅動程式與所有著色器搭配使用。 如果其中任何著色器有不同的根簽章,則會由在 API 中傳入的根簽章取代。 如果未傳入根簽章,傳入的所有著色器都必須有根簽章,而且必須相符 –這會提供給驅動程式。 在命令清單或套件組合上設定 PSO 並不會變更根簽章。 這是由 SetGraphicsRootSignatureSetComputeRootSignature方法完成。 在叫用繪製 (圖形) /dispatch (計算) 時,應用程式必須確定目前的 PSO 符合目前的根簽章;否則,行為為未定義。

定義 1.1 版根簽章的程式碼

下列範例示範如何使用下列格式建立根簽章:

RootParameterIndex 目錄
[0] 根常數: { b2 } (1 CBV)
 [1] 描述項資料表: { t2-t7, u0-u3 } (6 個 SRV + 4 個 UAV)
[2] 根 CBV: { b0 } (1 CBV、靜態資料)
[3] 描述項資料表: { s0-s1 } (2 個取樣器)
[4] 描述中繼資料表: { t8 - 未系結 } (未系結的 SRV、volatile 描述元)
[5] 描述項資料表: { (t0, space1) - 未系結 } (未系結的 SRV、volatile 描述元)
[6] 描述中繼資料表: { b1 } (1 CBV,靜態資料)

 

如果大部分的根簽章大部分時間都使用,則比必須太頻繁地切換根簽章更好。 應用程式應該從最常變更為最少的根簽章中排序專案。 當應用程式將系結變更為根簽章的任何部分時,驅動程式可能必須複製部分或所有根簽章狀態的複本,當乘以許多狀態變更時,可能會變成非簡單的成本。

此外,根簽章會定義靜態取樣器,該取樣器會在著色器暫存器暫存器 s3 上執行異質紋理篩選。

系結此根簽章之後,就可以將描述中繼資料表、根 CBV 和常數指派給 [0..6] 參數空間。 例如,描述中繼資料表 (描述元堆積中的範圍) 可以系結在每個根參數 [1] 和 [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));

下列程式碼說明在圖形命令清單中如何使用上述根簽章。

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(...);
}

根簽章

在 HLSL 中指定根簽章

使用根簽章