Skip to main content
XG 記憶體 (XG Memory) 是一個輔助執行階段程式庫,用於為 Microsoft Game Development Kit (GDK) 遊戲建立特殊的記憶體對應。它的設計是作為舊版遊戲作業系統中隨 Direct3D 11.X API 引進的數種不同 ESRAM 對應方法的後繼者。對於 XBOX One 上的 Direct3D 12.X,我們建議使用 XG 記憶體來存取高速 ESRAM 記憶體。 本概觀說明 XG 記憶體的元件,以及它們如何與系統記憶體對應 API 搭配運作。XG 記憶體以原始程式碼形式 (全部為內嵌) 提供於 Gaming eXtensions Development Kit (GXDK) 中的 xgmemory.h 和 xgmemory.inl,因此可在必要時進行自訂。

設計理念

基本上,XG 記憶體是將實體記憶體頁面 (包括系統頁面和 ESRAM 頁面) 對應至虛擬位址範圍的一種解決方案。Microsoft Game Development Kit (GDK) 遊戲作業系統和圖形驅動程式堆疊提供 XMemVirtualAlloc 和 XMemAllocatePhysicalPages 等低階 API 來執行這些作業,但它們可能難以有效使用。XG 記憶體建置在低階 API 之上,並以下列原則進行設計。
  1. 提供高階、易於使用的 API,讓所有遊戲都能將其用於 D3D12.X 甚至 D3D11.X 開發。同時隨附原始程式碼,以便在必要時檢查和改善底層的複雜性。
  2. 在設計時考量對動態記憶體配置的支援。現代遊戲越來越多地採用動態解析度和其他需要在執行階段頻繁重新對應記憶體配置的技術。
  3. 在設計時考量支援在同一個畫面中輕鬆重新對應記憶體。有效率地使用 ESRAM 需要採用一些策略,讓不同的資源在未同時使用時可以共用相同的記憶體頁面。
  4. 確保更清楚地區分資源之間的「記憶體別名」與「資料別名」,以便於工具處理。記憶體別名是指兩個資源共用相同的記憶體,但記憶體中的資料永遠不會由兩個資源同時檢視以重新解譯。資料別名是指兩個資源共用相同的記憶體,但有意以兩種不同的方式重新解譯其中的資料。
Direct3D 11.X 的舊版 ESRAM API 一律將 ESRAM 視為連續的記憶體區塊,這大幅限制了在兩個或多個資源之間共用 ESRAM 的彈性。當必須調整任何資源的 ESRAM 用量時,舊版 API 也會增加複雜性,其他資源必須修正以配合這些變更。XG 記憶體是專為解決這些問題而設計的,因為它以頁面而非範圍為單位運作。此外,它還會替您進行計算,在需要的地方正確配置頁面。

XG 記憶體 API 物件

XG 記憶體 API 有三個 API 物件:引擎、配置和對應。
  1. 引擎 (XGMemoryLayoutEngine 類別) 是代表您指派給一或多個記憶體配置之記憶體預算的物件。它會儲存將對應至配置的 ESRAM 和/或系統記憶體實體頁面清單。配置物件也是在此建立的。
  2. 配置 (XGMemoryLayout 類別) 是代表單一記憶體配置的物件,由保留的虛擬位址範圍及其中的多個對應所組成。雖然每個引擎可以建立任意數量的配置,但在任何指定時間,每個引擎都應只有一個配置在使用中。來自同一個引擎的配置會共用相同的實體記憶體頁面。
  3. 對應 (XGMemoryLayoutMapping 結構) 代表將一組實體頁面單一對應至配置內的虛擬位址範圍。建構對應之後,可以在對應的虛擬位址上以放置方式建立一或多個圖形資源。

XG 記憶體逐步解說和使用範例

準備使用 XG 記憶體

在開始使用 XG 記憶體之前,請思考您的遊戲以及 XG 記憶體適合的位置。您是否只有一兩個資源需要使用 ESRAM?您是否有整個子系統需要透過共用來減少記憶體使用量?您能否在同一個地方設定引擎的所有轉譯目標?放入同一個配置的資源越多,以及記憶體共用的機會越明顯,XG 記憶體就越有用。XG 記憶體的配置設計也最適合以「循序」方式 (在同一個執行緒上以一系列連續步驟) 設定轉譯目標資源的引擎。

步驟 1:建立 XG 記憶體配置引擎

首先,建立一個引擎,其中包含您要用於所有將使用 XG 記憶體建立之資源的實體記憶體上限。例如,您可能想要建立具有 32 MB (512 個頁面) ESRAM 和另外 64 MB (1024 個頁面) 系統記憶體的引擎。建立引擎時,您可以傳入從 XMemAllocatePhysicalPages 預先配置的實體頁碼清單,也可以指示 XG 記憶體代您呼叫 XMemAllocatePhysicalPages。ESRAM 頁碼可以輕鬆地使用索引 0-511 產生,用來指稱構成整個 ESRAM 的 512 個 64 KB 頁面。

步驟 2:建立 XG 記憶體配置

接著,考量您打算設定的所有資源的虛擬大小總計,包括共用 (也就是重疊部分重複計算)。例如,我們可以建立具有 128 MB 虛擬位址空間的配置,以涵蓋大約 10 個 1080p 32 bpp 目標再加上一些額外空間。這個數字即使高估,代價也很小,因為建立配置只是保留虛擬位址空間。保留虛擬位址空間的成本非常低,而且您有數百 GB 的虛擬位址空間可用。虛擬位址保留是透過以 MEM_RESERVE 呼叫 XMemVirtualAlloc 來完成。 除了保留虛擬位址空間之外,配置還包含從引擎取得的實體記憶體頁面可用清單。建立對應時,會以後進先出 (LIFO) 的方式從可用清單取得頁面。

步驟 3:建立對應和放置資源

針對您要設定的每個資源,使用 XG 程式庫判斷資源在虛擬位址空間中的大小,然後無條件進位並相除,以取得 64 KB 頁面數。XG 記憶體配置類別有數個建立對應的方法,但它們都有一個共同的概念。對於每個對應,您會指定將實體頁面認可至對應時要使用的 ESRAM 頁面數和系統記憶體頁面數。各種對應建立 API 的差異只在於要產生的對應模式的複雜度 (ESRAM 頁面和系統頁面在整個對應中的特定順序)。在內部,XG 記憶體會結合使用 XMemMapPhysicalPages 和 D3DMapEsramPages,分別將系統頁面和 ESRAM 頁面認可至配置中保留的虛擬位址空間。 建立對應之後,您可以使用 XGMemoryLayoutMapping 結構的 MappingBaseAddress 成員,作為放置資源建立 API (例如 ID3D12Device::CreatePlacedResourceX) 的輸入。請記住,XBOX One 上的圖形虛擬位址在 CPU 和 GPU 之間是一致的,因此您可以將 UINT64 位址值轉換為 void*,反之亦然。

步驟 4:(選擇性) 放棄對應以重複使用實體頁面

如果您想要在兩個或多個資源之間共用頁面,可以「放棄」一個對應,將其實體頁面放回配置內的可用清單。請注意,放棄作業不會解除認可對應的記憶體。它允許將認可至該對應的頁面重新指派給新的對應。因此,放棄對應之後,一旦與後續對應相關聯的記憶體開始使用,您就不能再使用該對應的記憶體。放棄可以視為某次記憶體使用與同一記憶體另一次使用之間的屏障。放棄也有助於工具處理和推斷意圖,因為記憶體只在實體層級重複使用,而不是在虛擬層級。這兩個不同的對應具有唯一的虛擬位址。如果您想要刻意為記憶體建立別名 (例如,將色彩目標重疊到樣板緩衝區上以快速填滿樣板),應該使用同一個對應的相同虛擬位址建立兩個放置資源來達成。

案例虛擬程式碼

請考慮下列虛擬 API 呼叫序列,假設已建立記憶體配置引擎。
  1. CreateLayout(“Rendertargets”, WorstCaseTotalPageCount, &layout)
  2. CreateMapping(“Shadow Map”, &mapping1)
  3. Map(mapping1, ShadowMapPageCount, ShadowMapEsramPageCount)
  4. CreatePlacedResourceX(mapping1.address, ShadowMapDesc, &pShadowMapResource)
  5. CreateMapping(“Color Target”, &mapping2)
  6. Map(mapping2, ColorTargetPageCount, ColorTargetEsramPageCount)
  7. CreatePlacedResourceX(mapping2.address, ColorTargetDesc, &pColorTargetResource)
  8. RelinquishMapping(mapping1)
  9. CreateMapping(“Post Effects Target”, &mapping3)
  10. Map(mapping3, PostEffectsPageCount, PostEffectsEsramPageCount)
  11. CreatePlacedResourceX(mapping3.address, PostEffectsDesc, &pPostEffectsResource)
此序列會建立三個轉譯目標:陰影對應、色彩目標和後製效果目標。透過放棄功能,陰影對應和後製效果目標會共用相同的記憶體。請注意,遊戲在此不需要進行相依的計算。所有配置都會在依序建立每個對應時由配置計算。 現在假設您已進行一些分析,並決定需要更新資源之間的 ESRAM 頁面分配。色彩目標需要更多 ESRAM。您只需要減少 ShadowMapEsramPageCount 值並增加 ColorTargetEsramPageCount 值即可。其餘部分由 XG 記憶體處理,ESRAM 頁面會彈性地從陰影對應和後製效果目標重新配置給色彩目標。請注意,在建立配置期間的任何時間,都可以取得目前的可用 ESRAM 頁面數和可用系統頁面數。 如果您需要在序列中插入新的轉譯目標,也可以使用相同的技巧。例如,我們可以如下所示,將第四個對應 (深度目標) 新增至配置中。
  1. CreateLayout(“Rendertargets”, WorstCaseTotalPageCount, &layout)
  2. CreateMapping(“Shadow Map”, &mapping1)
  3. Map(mapping1, ShadowMapPageCount, ShadowMapEsramPageCount)
  4. CreatePlacedResourceX(mapping1.address, ShadowMapDesc, &pShadowMapResource)
  5. CreateMapping(“Color Target”, &mapping2)
  6. Map(mapping2, ColorTargetPageCount, ColorTargetEsramPageCount)
  7. CreatePlacedResourceX(mapping2.address, ColorTargetDesc, &pColorTargetResource)
  8. CreateMapping(“Depth Target”, &mapping4)
  9. Map(mapping4, DepthTargetPageCount, DepthTargetEsramPageCount)
  10. CreatePlacedResourceX(mapping4.address, DepthTargetDesc, &pDepthTargetResource)
  11. RelinquishMapping(mapping1)
  12. CreateMapping(“Post Effects Target”, &mapping3)
  13. Map(mapping3, PostEffectsPageCount, PostEffectsEsramPageCount)
  14. CreatePlacedResourceX(mapping3.address, PostEffectsDesc, &pPostEffectsResource)
請注意,周圍的程式碼不需要做任何變更。新增對應時,您可能需要在其他對應之間重新平衡 ESRAM 頁面數,但永遠不需要擔心連續範圍、虛擬位址重疊或任何其他相依的計算。 接下來,假設您需要動態變更轉譯目標的大小以進行動態解析度變更。不過,您已經妥善平衡了所有資源之間的 ESRAM 使用量,而且不想重新調整該平衡。這對 XG 記憶體來說不成問題,只需調整頁面數變數 (ShadowMapPageCount、ColorTargetPageCount 等) 即可。其餘部分由 XG 記憶體處理,並保持您的 ESRAM 配置不變。您只需要確保 WorstCaseTotalPageCount 值夠大,足以處理所有資源的最大設定即可。

結論

XG 記憶體可以大幅降低在 XBOX One 上使用 ESRAM 的複雜性。此外,即使是需要重複使用頁面、但百分之百由系統頁面組成的記憶體配置,它也能派上用場。 歡迎透過 Game Developer Support 提供有關 XG 記憶體的意見反應。

另請參閱

d3d12_x
Last modified on October 6, 2026