線性伸縮空間段類似于線性內存空間段。 但是,伸縮空間段只是地址空間,不能容納位。
若要保存位,必須分配系統內存頁,并且必須重定向地址空間范圍以引用這些頁面。 內核模式顯示微型端口驅動程序(KMD)必須實現 DxgkDdiBuildPagingBuffer 函數,以便DXGK_OPERATION_MAP_APERTURE_SEGMENT和DXGK_OPERATION_UNMAP_APERTURE_SEGMENT操作類型來處理重定向,并且必須按 Display Miniport Driver Driver Driver 的 DriverEntry 中所述公開此函數。 Dxgkrnl 使用要重定向的地址空間范圍和引用已分配的物理系統內存頁的 MDL 調用 DxgkDdiBuildPagingBuffer 。
KMD 通常通過編程頁表(對于視頻內存管理器(VidMm)未知)來實現地址空間范圍的重定向。
驅動程序必須在DXGK_SEGMENTDESCRIPTOR結構的 Flags 成員中設置 Aperture 位字段標志,以指定線性伸縮空間段。 驅動程序還可以設置以下位字段標志來指示其他段支持:
- CpuVisible 指示該段是 CPU 可訪問的。
- CacheCoherent 指示該段與段重定向到的頁面的 CPU 保持緩存一致性。
下圖顯示了線性光圈空間段的可視表示形式。
?1. 核心特性
特性 | 說明 |
---|---|
虛擬地址空間 | 僅為地址范圍,不包含實際內存(需動態映射物理頁)。 |
動態重定向 | 通過?DxgkDdiBuildPagingBuffer ?將虛擬地址綁定到系統內存頁(MDL 描述)。 |
CPU 默認可見 | 通常用于 CPU 頻繁訪問的資源(如動態緩沖區)。 |
緩存一致性可選 | 通過?CacheCoherent ?標志保持 CPU-GPU 緩存同步 |
?2. 段描述符配置(DXGK_SEGMENTDESCRIPTOR)
(1) 基礎配置
DXGK_SEGMENTDESCRIPTOR Segment = {.Flags = DXGK_SEGMENT_FLAGS_APERTURE, // 聲明為光圈段.BaseAddress = 0x10000000, // 虛擬地址起始.Size = 0x20000000, // 512MB.SegmentId = 2,
};
(2) 可選標志
標志 | 作用 | 適用場景 |
---|---|---|
DXGK_SEGMENT_FLAGS_CPU_VISIBLE | 允許 CPU 訪問(通常默認啟用) | CPU-GPU 共享數據 |
DXGK_SEGMENT_FLAGS_CACHE_COHERENT | 強制緩存一致性 | 避免手動刷新緩存(如 ARM GPU) |
示例(緩存一致的線性光圈段):
{.Flags = DXGK_SEGMENT_FLAGS_APERTURE | DXGK_SEGMENT_FLAGS_CACHE_COHERENT,.BaseAddress = 0x30000000,.Size = 0x10000000, // 256MB.SegmentId = 3,
}
3. 內存映射流程
(1) 分配虛擬地址范圍
- 應用程序請求內存(如 ID3D12Resource 創建)。
- VidMm 選擇伸縮段,分配虛擬地址(GPU VA)。
(2) 物理頁綁定(重定向)
VidMm 調用 DxgkDdiBuildPagingBuffer,傳入:
- 操作類型:DXGK_OPERATION_MAP_APERTURE_SEGMENT(映射)或 UNMAP(解除映射)。
- MDL(Memory Descriptor List):描述系統內存物理頁。
- 虛擬地址范圍:需綁定的 GPU VA。
KMD 實現重定向:
- 編程 GPU 頁表,將 GPU VA 映射到 MDL 中的物理頁。
- 若啟用 CACHE_COHERENT,需配置 GPU 緩存策略。
代碼示例(映射操作):
NTSTATUS DxgkDdiBuildPagingBuffer(DXGKARG_BUILDPAGINGBUFFER* pArgs) {if (pArgs->Operation == DXGK_OPERATION_MAP_APERTURE_SEGMENT) {// 獲取 MDL 中的物理頁PHYSICAL_ADDRESS physAddr = MmGetMdlPfnArray(pArgs->pMdl)[0];// 編程 GPU 頁表ProgramGpuPageTable(pArgs->VirtualAddress, physAddr);}return STATUS_SUCCESS;
}
4. 典型應用場景
(1) 動態頂點/索引緩沖區
需求:CPU 每幀更新數據,GPU 讀取。
配置:
{.Flags = DXGK_SEGMENT_FLAGS_APERTURE | DXGK_SEGMENT_FLAGS_CACHE_COHERENT,.BaseAddress = 0x20000000,.Size = 0x08000000, // 128MB
}
(2) 分頁資源(Pageable Resources)
需求:按需加載大型紋理。
流程:
- 初始分配虛擬地址(不綁定物理頁)。
- 訪問時觸發缺頁中斷,VidMm 調用 DxgkDdiBuildPagingBuffer 動態映射。
(3) 多 GPU 共享資源
- 需求:數據在多個 GPU 間遷移。
- 優勢:虛擬地址固定,僅需更新物理頁映射。
5. 驅動開發注意事項
(1) 頁表管理
- GPU 頁表獨立于 CPU:需驅動自行維護 GPU MMU(內存管理單元)的頁表。
- TLB 一致性:映射/解除映射后,需無效化 GPU TLB(如通過 DXGK_INVALIDATE_TLB)。
(2) 性能優化
- 批處理映射操作:合并多次映射請求,減少 GPU 上下文切換。
- 避免過度分片:盡量分配連續物理頁(減少頁表項數量)。
(3) 錯誤處理
- 物理頁不足:返回 STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER。
- 非法虛擬地址:驗證 VirtualAddress 是否在段范圍內。
6. 與線性內存空間段的對比
特性 | 線性光圈空間段 | 線性內存空間段 |
---|---|---|
物理內存 | 動態綁定系統內存頁 | 直接分配顯存 |
地址轉換 | 需 GPU 頁表映射 | 直接訪問(無轉換) |
CPU 訪問 | 默認支持 | 需顯式啟用 (CPU_VISIBLE ) |
性能 | 較低(轉換開銷) | 高(零開銷) |
適用場景 | CPU 頻繁寫、分頁資源 | 高性能渲染目標 |
7. 可視化表示
GPU 虛擬地址空間:
0x10000000 ┌───────────────────────┐ ← 光圈段起始(BaseAddress)│ Virtual Range │ │ (No Physical Memory)│ ├───────────────────────┤ ← 映射操作后│ Mapped to │ │ System Memory (MDL) │ ← 物理頁動態綁定
0x30000000 └───────────────────────┘ ← 段結束
8. 總結
線性伸縮空間段 = 虛擬地址 + 動態物理頁綁定,適用于需靈活內存管理的場景。
關鍵驅動實現:
- 處理 DXGK_OPERATION_MAP_APERTURE_SEGMENT/UNMAP 操作。
- 維護 GPU 頁表,確保地址轉換正確。
優勢:
- 支持 CPU 高效讀寫。
- 實現按需分頁和資源共享。
通過合理使用伸縮段,驅動程序可以在保證功能性的同時,優化復雜應用場景下的內存利用率。