2017-07-25 92 views
0

因此,在觀看dx12綁定視頻並閱讀某些文檔後,如果我正確理解如何管理堆,我不能100%確定。DX12描述符堆管理

讓我解釋一下我在我的應用程序中無法達到的效果: 初始化期間,我將填充兩個堆,一個拿着取樣器,另一個拿着SRV,CBV和UAV。 這些堆將包含應用程序在其生命週期中將使用的所有資源。

現在開始有趣的部分。爲了構建根簽名,我將主要使用根描述符表。我們知道,表格將保存範圍,範圍是基礎着色器槽,描述符的數量和其他設置。 讓我告訴你,例如:

Root Parameters 
0 - root_table 
1 - root_table 

0 root_table 
CBV b1 
CBV b6 
SRV t0 
SRV t2 

1 root_table 
Sampler s1 
Sampler s4 

如示例所示,還可以有一個是不連續的(例如B0,B1,B2和B3),但是,命令列表錄製過程中,我們只能範圍這樣做:

ID3D12DescriptorHeaps* heaps[2] = {mCbvSrvUavHeap,mSamplerHeap}; 
mCmdList->SetDescriptorHeaps(2,heaps); 

mCmdList->SetGraphicsRootDescriptorTable(0, mCbvSrvUavHeapGpuHanleStart); 
mCmdList->SetGraphicsRootDescriptorTable(1, mSamplerHandleHanleStart); 

這意味着,我們必須mCbvSrvUavHeapmSamplerHeap正確下令描述。

例如:

mCbvSrvUavHeap 
CBV 
CBV 
SRV 
SRV 

這裏是哪裏出了問題對我來說。正如我最初所說,我將爲應用程序創建兩大堆,但是,我不能將這些堆設置到命令列表中,因爲它們將具有其他不會使用的描述符!

我該如何處理?我是否需要創建一個僅包含我將使用的描述符的新Heap?

希望我解釋清楚!

+0

如果您願意使用額外的rootig插槽,則它們不需要連續。 [Here's](https://github.com/Microsoft/DirectXTK12/blob/master/Src/Shaders/RootSig.fxh)我在[DirectX Tool Kit for DirectX 12]中使用的根目錄(https://github.com/)微軟/ DirectXTK12)。我不是說他們是最優的,但他們完成了工作。 –

回答

1

你對此理解錯誤。描述符堆不是不可變的東西,而是不斷變化的對象。當你綁定一個描述符表時,你實際上是從任何偏移量來綁定它的。交換描述符堆是您想要不惜一切代價避免的代價高昂的操作。

的想法是準備在非GPU可見堆描述符(儘可能多的,只要你喜歡,他們僅僅是CPU分配的對象)和按需複製到GPU可見一個在一個環形緩衝區時尚的方式與CopyDescriptorCopyDescriptorSimple

假設你的着色器使用一個帶有2個CBV和2個SRV的表,它們必須在堆中連續,所以你將從你的堆中分配一個4的數組,你得到一個堆偏移量,複製需要的描述符和綁定它與SetGraphicsRootDescriptorTable

你必須小心的一件事是你堆中描述符的生存期,因爲你不能覆蓋它們,直到GPU完成處理使用它們的命令爲止。最後,如果許多着色器使用相似的根簽名共享一些常用表,則可以通過分解更新來節省處理時間。

+0

這當然是一種策略,但改變描述符堆並不一定是世界末日,取決於發生了什麼。是的,它會在某些硬件上導致管道刷新,但這可能並不是那麼糟糕,因爲您必須將其與其他供應商的最佳實踐進行折衷。 –

+0

對於nvidia來說(70%的個人電腦市場),「如果你想瞄準運行並行異步計算和圖形工作負載,確保只使用一個CBV/SRV/UAV /描述符堆作爲所有幀的環形緩衝區,我的理解是,它們將在描述符堆之間存在障礙,這將像在每個Draw調用之間插入一個'WaitForIdle'並且放鬆所有並行機會。 – galop1n

+0

我想到了在後臺有一個環形緩衝區的想法,所以我可以做雙/三重緩衝,而不必籬笆每幀:)。感謝您的解釋,這真的很有幫助。我想我會做以下事情:用SRV_UAV_CBV和另一個用於採樣器的大堆(非着色器可見),然後用下一個繪製/分派的描述符構建「當前」描述符堆。一旦我完成了這個新的堆,我應該調用ID3D12Descriptorheap :: Release()對不對? – Nacho