資源管理最佳做法
自第 6 版起,DirectX 中已有稱為自動紋理管理的受控紋理,後續版本有數個修訂和增強功能。 從 Direct3D 9 API 發行開始,自動資源管理包含紋理、頂點緩衝區和索引緩衝區的支援,全都具有一致的共用介面。 藉由使用 Direct3D 資源管理員,應用程式可以大幅簡化遺失裝置狀況的處理,並依賴系統來處理合理數量的過度承諾視訊記憶體資源。
開發人員有時會因為系統的抽象本質而難以使用受控資源。 雖然許多常見的資源案例都適合受控資源,但某些案例在使用 Unmanaged 資源時會執行得更好。 本文討論一般處理資源的最佳做法、Managed 和 Unmanaged 資源的運作方式,並提供執行時間和驅動程式通常如何處理資源的一些詳細資料。
本文涵蓋下列概念:
視訊記憶體
若要讓視訊系統使用資源,它必須位於 GPU 可存取的記憶體中。 本機視訊記憶體為 GPU 提供最佳效能,而某些資源 (例如轉譯目標和深度/樣板緩衝區) 必須位於本機視訊記憶體中。 隨著 AGP 的問世,GPU 也可以直接存取系統記憶體的一部分。 此記憶體區域稱為 AGP 光圈,稱為非本機視訊記憶體,不適用於其他用途。 非本機視訊記憶體可由 CPU 讀取和寫入,其通常沒有本機視訊記憶體的高效能存取權,因此非常適合作為共用記憶體資源使用。 要記住有關 AGP 記憶體的重要事項是,它就像本機視訊記憶體一樣,在遺失裝置的情況下失效,而且必須還原該處的持續資產。
圖 1. GPU、CPU、視訊 RAM 和系統 RAM 的關聯性
某些整合式視訊解決方案會使用 UMA) (統一記憶體架構,其中主要記憶體可由系統的所有元件定址。 Direct3D 支援 UMA,而不需要對應用程式進行任何變更,使用與本機視訊記憶體設定相同的提示。 對於這類系統,資源一律位於系統記憶體中,而驅動程式負責確保資源的運作方式與在較傳統的架構中非常類似,同時利用 UMA 的屬性和硬體實作的任何特定行為。
圖 2. GPU 和 CPU 具有統一記憶體架構中系統 RAM 的相等存取權
Managed 資源
大部分的資源都應該在 POOL_MANAGED中建立為受控資源。 您的所有資源都會在系統記憶體中建立,然後視需要複製到視訊記憶體中。 遺失裝置的情況會自動從系統記憶體複本處理。 由於並非所有 Managed 資源都需要一次放入視訊記憶體中,因此您可以過度認可記憶體,其中較小的視訊記憶體工作集是在任何指定畫面中轉譯所需的所有資源。 請注意,大部分的備份存放區系統記憶體可能會隨著時間分頁到磁片,這就是為什麼重設作業可能會因為需要重新分頁此資料以還原遺失的視訊記憶體而變慢的原因。
執行時間會在上次使用資源時保留時間戳,而且當視訊記憶體配置載入所需的受控資源失敗時,它會以 LRU 方式根據此時間戳記釋放資源。 SetPriority的使用優先順序高於時間戳記,因此較常用的資源應該設定為較高的優先順序值。 Direct3D 9.0 具有驅動程式所管理視訊記憶體的有限資訊,因此執行時間可能需要收回數個資源,才能建立足夠的區域,以便配置成功。 適當的優先順序有助於消除收回某個專案的情況,然後在不久之後再次需要。 應用程式也可以呼叫 EvictManagedResources ,強制移除所有受控資源。 同樣地,這可以是重載下一個畫面所需的所有資源相當耗時的作業,但對於工作集大幅變更和移除視訊記憶體片段的層級轉換非常有用。
畫面格計數也會保留下來,以允許執行時間偵測它剛選擇收回的資源是否在目前框架早期使用,這表示在單一畫面格中使用的資源數目超過會放入視訊記憶體的情況。 這會觸發取代原則,以切換為 MRU 方式,而不是在框架的其餘部分使用 LRU,因為這樣在這類情況下執行效能較佳。 這類擲除行為會大幅影響轉譯效能。 請注意,目前框架的概念會系結至 EndScene,因此任何使用 Managed 資源的應用程式都需要對此方法進行一般呼叫。
想要尋找受控資源在其應用程式中如何運作的詳細資訊,可以透過 IDirect3DQuery9 介面使用 RESOURCEMANAGER 事件查詢。 這僅適用于使用偵錯執行時間時,因此此資訊無法由應用程式相依,但會提供執行時間所管理之資源的深入詳細資料。
雖然瞭解資源管理員的運作方式有助於調整和偵錯應用程式,但請務必不要將應用程式緊密系結至目前執行時間或驅動程式的實作詳細資料。 硬體中驅動程式或變更的修訂可能會大幅變更行為,而未來的 Direct3D 版本將會大幅改善且複雜的資源管理。
Driver-Managed資源
Direct3D 驅動程式是免費的,可實作驅動程式管理的紋理功能,由D3DCAPS2_CANMANAGERESOURCE表示,這可讓驅動程式處理資源管理,而不是執行時間。 對於實作此功能的 (罕見) 驅動程式,驅動程式的資源管理員確切行為可能會有很大的差異,您應該連絡驅動程式廠商,以取得其實作方式的詳細資訊。 或者,您可以藉由在建立裝置時指定D3DCREATE_DISABLE_DRIVER_MANAGEMENT,以確保一律使用運行時間管理員。
預設資源
雖然受控資源簡單、有效率且容易使用,但有時候直接使用視訊記憶體還是甚至必要。 這類資源會建立在 POOL_DEFAULT 類別中。 使用這類資源會造成應用程式的額外複雜性。 需要程式碼才能處理所有POOL_DEFAULT資源的遺失裝置情況,而且在將資料複製到其中時,必須考慮效能考慮。 無法指定USAGE_WRITEONLY或讓轉譯目標鎖定也可能會造成嚴重的效能負面影響。
除非使用特定提示旗標,否則呼叫POOL_DEFAULT資源的 鎖定 ,更可能會造成 GPU 停止運作,而不是使用POOL_MANAGED資源。 根據資源的位置,傳回的指標可以是暫存系統記憶體緩衝區,也可以是直接指向 AGP 記憶體的指標。 如果是暫存系統記憶體緩衝區,則 解除鎖定 呼叫之後,資料必須傳輸到視訊記憶體。 如果視訊資源不是僅寫入,則資料必須在 鎖定期間傳送到暫存緩衝區。 如果是 AGP 記憶體區域,則會避免暫存複本,但所需的快取行為可能會導致效能變慢。
請小心將完整快取資料行寫入 AGP 光圈記憶體的任何指標,以避免寫入合併的負面影響,這會導致讀寫迴圈,而且偏好循序存取記憶體區域。 如果您的應用程式需要在建立期間隨機存取資料,而且您不想對緩衝區使用受控資源,您應該改用系統記憶體複本。 建立資料之後,您就可以將結果串流至鎖定的資源記憶體,以避免對快取寫入合併作業支付高費用。
LOCK_NOOVERWRITE旗標可用來為某些資源以有效率的方式附加資料,但理想情況下,可以避免對相同資源的多個 鎖定 和 解除鎖定 呼叫。 適當地使用各種鎖定旗標對於最佳效能很重要,如同在填滿鎖定記憶體時使用資料存取的快取易記模式。
同時使用受控和預設資源
混合受控和POOL_DEFAULT資源的配置可能會導致視訊記憶體片段,並混淆執行時間對受控資源可用的視訊記憶體檢視。 在理想情況下,您應該先建立所有POOL_DEFAULT資源,再使用POOL_MANAGED資源或使用 EvictManagedResources 呼叫,再配置 Unmanaged 資源。 請記住,從位於視訊記憶體中的POOL_DEFAULT配置,會將記憶體系結到資源管理員無法使用或用於任何其他用途的資源。
請注意,不同于舊版 Direct3D,第 9 版執行時間會在放棄缺少視訊記憶體的失敗非受控資源配置之前自動收回某些受控資源,但這可能會建立額外的片段,甚至強制資源進入子最佳位置 (,例如,在非本機視訊記憶體中具有靜態紋理) 。 同樣地,最好先配置所有必要的非受控資源,再使用任何受控資源。
動態預設資源
以高頻率產生和更新的資料不需要備份存放區,因為還原裝置時會重新建立所有資訊。 這類資料通常會在POOL_DEFAULT中建立,並指定USAGE_DYNAMIC提示,讓驅動程式可以在放置資源時做出優化決策,知道資源會經常更新。 這通常表示將資源放入非本機視訊記憶體,因此,GPU 存取速度通常比本機視訊記憶體慢很多。 針對 UMA 架構,驅動程式可能會為動態資源選擇特定的位置,以針對 CPU 寫入存取進行優化。
這種使用方式通常適用于填滿頂點/索引緩衝區的軟體外觀解決方案和以 CPU 為基礎的物件系統,而LOCK_DISCARD旗標可確保在資源仍在使用前一個畫面格的情況下,不會建立停止。 在此情況下,使用 Managed 資源會更新系統記憶體緩衝區,然後複製到視訊記憶體,然後只用于框架或兩個畫面,再被取代。 對於具有非本機視訊記憶體的系統,會藉由適當地使用此動態模式來消除額外的複本。
標準紋理無法鎖定,而且只能透過 UpdateSurface 或 UpdateTexture更新。 有些系統支援動態紋理,可以鎖定並使用LOCK_DISCARD模式,但必須先檢查功能位 (D3DCAPS2_DYNAMICTEXTURES) ,才能使用這些資源。 針對 (視訊或程式性) 的高度動態紋理,您的應用程式可以使用 UpdateTexture來建立相符POOL_DEFAULT和POOL_SYSTEMMEM資源,並處理視訊記憶體更新。 對於高度頻繁和部分更新, UpdateTexture 範例可能是較佳的選擇。
與動態資源一樣有用,在設計高度依賴動態提交的系統時,請小心。 靜態資源應該放在POOL_MANAGED,以確保本機視訊記憶體的使用率良好,以及更有效率地使用有限的匯流排和主要記憶體頻寬。 對於半靜態的資源,您可能會發現偶爾上傳至本機視訊記憶體的成本遠小於動態產生的固定匯流排流量。
系統記憶體資源
您也可以在POOL_SYSTEMMEM中建立資源。 雖然圖形管線無法使用它們,但可以使用 UpdateSurface 或 UpdateTexture作為更新POOL_DEFAULT資源的來源。 其鎖定行為很簡單,但如果其中一個先前提及的方法正在使用中,則可能會發生停頓。
雖然它們位於系統記憶體中,POOL_SYSTEMMEM資源受限於相同的格式和功能, (例如設備磁碟機所支援的大小上限) 。 POOL_SCRATCH資源類型是另一種系統記憶體資源形式,可利用執行時間支援的所有格式和功能,但裝置無法存取。 臨時資源主要是供內容工具使用。
圖 3. 影片 RAM、AGP 光圈和系統 RAM 中的記憶體資源
一般建議
取得資源管理正確的技術實作詳細資料,將能長期達成應用程式的效能目標。 規劃資源如何呈現給 Direct3D,以及以及時方式載入資料的架構設計是更複雜的工作。 針對您的應用程式做出這些決策時,建議您使用一些最佳做法:
- 預先處理所有資源。 在開發期間,依賴資源的昂貴負載時間轉換和優化是很方便的,但這麼做會對使用者的電腦造成絕佳的效能負擔。 預先處理的資源較快載入、更快速使用,並可讓您選擇執行複雜的離線工作。
- 避免為每個畫面建立許多資源。 所需的驅動程式互動可以序列化 CPU 和 GPU,而涉及的作業會很繁重,因為它們通常需要核心轉換。 分散在數個畫面格上建立,或重複使用資源,而不需建立/釋放資源。 在理想情況下,您應該先等候數個畫面格,再鎖定或釋放最近用來轉譯的資源。
- 在畫面結尾,請務必將所有資源通道解除系結 (,也就是串流來源、紋理階段和目前索引) 。 這麼做可確保在資源管理人員將實際不再使用的資源保留留存之前,會先移除對資源的暫留參考。
- 針對紋理,請使用壓縮格式 (例如,DXTn) 與 mip 對應,並考慮使用紋理地圖。 這些需求可大幅降低頻寬需求,並可減少資源的整體大小,因而使其更有效率。
- 針對幾何,請利用索引幾何,這可協助壓縮頂點緩衝區資源,而新式視訊硬體在重複使用頂點時大幅優化。 藉由利用可程式化的頂點著色器,您可以壓縮頂點資訊,並在頂點處理期間加以擴充。 同樣地,這有助於降低頻寬需求,並讓頂點緩衝區資源更有效率。
- 避免過度優化您的資源管理。 如果應用程式過度調整為特別組合,未來驅動程式、硬體和作業系統的修訂可能會造成相容性問題。 由於大部分的應用程式都是 CPU 系結,因此以 CPU 為基礎的管理通常會比解決更多的效能問題。
相關主題