GPU 虚拟地址

本文介绍 GPU 虚拟地址(GPUVA)概念,以及如何从 WDDM 2.0(Windows 10)开始管理它们。

GPUVA 在设备驱动程序接口 (DDI) 级别的逻辑 4 KB 或 64 KB 页面中进行管理。 使用这些页面大小,GPUVA 可以引用以下任一项:

  • 系统内存(始终以 4 KB 粒度分配)。
  • 内存段页可以按照 4 KB 或 64 KB 来管理。

视频内存管理器(VidMm)支持多级虚拟地址转换方案,其中多个级别的页表用于转换虚拟地址:

  • 级别从零开始编号。 级别零分配给叶级别。
  • 翻译从根级别页表开始。

当页表级别数为 2 时,可以调整根级别页表的大小以适应具有可变 GPUVA 空间大小的进程。 每个级别都由内核模式显示驱动程序(KMD)在 DxgkDdiQueryAdapterInfo 调用期间填充的DXGK_PAGE_TABLE_LEVEL_DESC结构进行描述。 KMD 还填写了描述 GPUVA 支持的 DXGK_GPUMMUCAPS 能力结构。

每个进程都有自己的 GPUVA 空间。 在可以设置进程的图形上下文以供执行之前,调用 KMD 的 DxgkDdiSetRootPageTable 函数来设置根页表地址。

下图显示了在两个页表级别情况下的虚拟地址转换。

显示两个页表级别的虚拟地址转换的图示。

  • GPUVA 包含 DXGK_GPUMMUCAPS::VirtualAddressBitCount 位。

  • 低位 [0 - 11] 表示页面中的偏移量(以字节为单位)。

  • 接下来的 DXGK_PAGE_TABLE_LEVEL_DESC::PageTableIndexBitCount 位表示叶子级页表中的页表项索引。

  • 页表中的条目数为 2DXGK_PAGE_TABLE_LEVEL_DESC::P ageTableIndexBitCount ,页表大小 为 DXGK_PAGE_TABLE_LEVEL_DESC::PageTableSizeInBytes 字节。

  • 其余位表示根页表中页表项的索引。 对于两级翻译方案,根页表可调整大小。 DxgkDdiGetRootPageTableSize DDI 获取其大小。

DXGK_PTE结构通过 DDI 来表示页表条目。 此结构表示 DirectX 图形内核 (Dxgkrnl) 管理的每个条目的相关信息。 驱动程序使用此信息生成特定于硬件的页表条目。

创建页表分配

页表作为隐式分配创建,并且没有用户模式驱动程序(UMD)或 KMD 句柄。

若要分配页表,VidMmDXGK_PAGE_TABLE_LEVEL_DESC::PageTableSegmentId指定的段中分配DXGK_PAGE_TABLE_LEVEL_DESC::PageTableSizeInBytes的空间。 创建后, VidMm 将页表中的每个条目初始化为 无效。 页表永远不会更改大小,但两级翻译方案中的根页表除外。

VidMm 支持在两级翻译方案中调整根页表的大小。 创建根页表(覆盖指定数量的地址空间)时, VidMm 会调用 DxgkDdiGetRootPageTableSize 来确定所需的分配大小。 然后,VidMm 在由 DXGK_PAGE_TABLE_LEVEL_DESC::PageTableSegmentId 指定的段中为根级别分配该大小的分配。 创建后,VidMm 使用新的 UpdatePageTable 分页操作将页面表中的每个条目初始化为无效状态。 当进程所需的虚拟地址空间扩展或收缩时,根页表可能会增大或缩小。 创建根页表后, VidMm 调用 DxgkDdiSetRootPageTable ,将新创建的根页表与将在其中执行的各种上下文相关联。

在链接显示适配器配置中,根页表将创建为 LinkMirrored 分配。 这些分配的内容相同,位于链接中每个 GPU 上的同一物理地址。 较低级别的页表被分配为 LinkInstanced 分配,以反映其内容可能会因不同图形处理器的对等映射差异而变化的事实。 页表的内容在所有 GPU 上单独更新。

扩展和缩小根页表

本部分仅适用于具有两个页表级别的系统。 当页表级别数大于 2 时,每个级别的页表大小由虚拟寻址上限定义,并且是固定的。

当 UMD 请求 GPUVA 时, VidMm 会增大进程的地址空间大小以适应请求。 这样做的方式是增大当前根页表的大小(如有必要),并为新范围分配新的页表。

若要扩展根页表 VidMm ,请创建另一个根页表分配,使其驻留、初始化其条目并销毁旧的分配。 DxgkDdiGetRootPageTableSize 函数用于获取新页表的大小(以字节为单位)。

为了收缩根页表, VidMm 会创建新的页表分配,使其驻留,将旧页表的一部分复制到新页表,并销毁旧的分配。

调整大小作完成后, VidMm 调用 DxgkDdiSetRootPageTable ,将受影响的上下文与其新的根页表相关联。

更新页表

当图面在内存中移动时, VidMm 会更新页表的内容以反映图面的新位置。

移动页表

* VidMm 可以在设备处于空闲或挂起状态时重新定位或逐出页表。 当 VidMm 移动页表时,它会更新更高级别的页表以引用页表的新位置。

重新定位根页表本身时, VidMm 调用 DxgkDdiSetRootPageTable ,以通知受影响的上下文其页面目录的新位置。

物理页面大小

如前所述, VidMm 支持两个页面大小。 系统内存始终在 4 KB 页中管理,而内存段可以按 KMD 确定的 4 KB 或 64 KB 粒度进行管理。

当选择在 64 KB 页面中管理虚拟内存时,所有分配都会自动对齐,大小设置为 64 KB 的倍数。

将所有分配扩展到 64 KB 可能会对内存产生重大影响。 UMD 负责将小型分配打包到更大的分配中,以避免浪费内存。

当 VidMm 将 GPUVA 映射到大型 64 KB 内存段页时,它会将 4 KB 页表条目映射到内存段中的 16 个连续 4 KB 页。 保证虚拟地址和物理地址共享相同的 64 KB 对齐方式。 也就是说,可以保证虚拟地址的底部 16 位和物理地址匹配。