描述項堆積概觀
描述項堆積包含許多不屬於管線狀態物件 (PSO) 的物件類型,例如著色器資源檢視 (SRV)、未排序的存取檢視 (UAV)、常數緩衝區檢視 (CBV) 和取樣器。
描述項堆積的目的
描述元堆積的主要用途是包含儲存著色器盡可能多轉譯視窗的物件型別描述元規格所需的大量記憶體配置(理想情況下是轉譯的整個框架或更多)。 如果應用程式正在切換管線從 API 快速看到哪些紋理,則必須在描述元堆積中有空間,才能針對所需的每個狀態集即時定義描述元數據表。 例如,如果資源再次用於另一個物件,或只是在切換各種物件類型時,依序指派堆積空間,應用程式可以選擇重複使用定義。
描述項堆積也允許個別軟體元件彼此分開管理描述元記憶體。
所有堆疊對CPU都是可見的。 應用程式也可以要求描述元堆積應該具有哪些 CPU 存取屬性(如果有的話)–寫入合併、回寫等等。 應用程式可以根據需要建立任意屬性及數量的描述符堆。 應用程式一律可以選擇建立單純用於暫存用途的描述元堆積,這些堆積的大小不受限制,並視需要複製到用於轉譯的描述元堆積。
在相同描述元堆積中可以執行的內容有一些限制。 CBV、UAV 和 SRV 專案可以位於相同的描述元堆積中。 不過,取樣器項目無法與 CBV、UAV 或 SRV 項目共用記憶體堆。 一般而言,有兩組描述元堆積,一組用於一般資源,第二組用於取樣器。
Direct3D 12 使用描述符堆反映了大多數 GPU 硬體的運作方式,也就是要求描述符只存在於描述符堆中,或是在使用這些堆時需要較少的位址位元。 Direct3D 12 確實需要使用描述元堆積,沒有選項可將描述元放在記憶體中的任何位置。
描述項堆積只能由 CPU 立即編輯,GPU 無法編輯描述元堆積。
同步
描述項堆積內容可以在記錄參考它的命令清單之前、期間和之後變更。 不過,在提交的命令清單可能會參考該位置的情況下,無法變更描述項,因為這可能會引發競爭狀況。
捆綁
最多在任何時刻只能結合一個 CBV/SRV/UAV 描述符堆和一個取樣器描述符堆以進行綁定。 這些堆積會在圖形和計算管線之間共用(如其 PSO 中所述)。
切換堆
應用程式可以使用 setDescriptorHeaps 和 Reset API,在相同命令清單中或不同命令清單中切換堆積。 在某些硬體上,這可能是一個耗費成本的操作,需要 GPU 停止並清空所有依賴於當前綁定描述符堆疊的工作。 因此,如果必須變更描述元堆積,當 GPU 工作負載相對較輕時,應用程式應該嘗試這樣做,或許會將變更限制在命令清單的開頭。
套裝
使用套件組合時,只能呼叫 SetDescriptorHeaps 方法,而且描述項堆積集必須完全符合呼叫套件組合的命令清單。 如果套件組合未變更描述元數據表,則不需要設定描述項堆積。
如需無法搭配套件組合使用的 API 呼叫清單,請參閱 建立和錄製命令清單和套件組合。
管理
若要在場景中轉譯所有物件,將需要許多描述項,而且有一些不同的管理策略可以遵循。
最基本的策略是填入描述元堆積的新區域,並填入下一個繪製呼叫的所有需求。 因此,在命令清單發出繪製指令之前,描述符表的指標將會設定到新填入的表的開頭。 缺點是不需要記錄任何特定描述元在堆積中的位置。
此策略的缺點是,描述元堆積中可能會有很多重複描述元,尤其是在呈現非常類似的場景時,而且描述元堆積空間將會很快用到。 為了避免衝突,可能需要單獨的描述符堆分別用於 GPU 上的渲染和 CPU 所記錄的操作。 或者,可以使用子分配系統。
此外,若要進一步優化基本系統,請在從一個繪製呼叫到下一個呼叫的過程中,小心使用重疊的描述符表,以便只新增所需的新描述符。
比基本策略更有效率的策略是預先填入描述元堆積,其中包含已知為場景一部分的物件(或材質)所需的描述項。 這裡的想法是,只需要在繪製時間設定描述元數據表,因為描述元堆積會事先填入。
預先填滿策略的變化是將描述元堆積視為一個巨大的數位列,其中包含固定已知位置中所有必要的描述項。 然後,繪製呼叫只需要接收一組常數,這些常數是索引到需要使用描述元的陣列中。
進一步的優化是確保根常數和根描述元包含最常變更的常數,而不是將常數放在描述項堆積中。 對於大部分的硬體而言,這是處理常數的有效方式。
實際上,圖形引擎可能會在不同情況下使用不同的策略,並結合每個策略的元素以符合特定的繪圖需求。
相關主題