window 显示驱动开发-处理内存段(二)
KMD 不需要在其内存段中指定 GPU 可用的所有视频内存资源。 但是,KMD 必须指定 VidMm 在系统上运行的所有进程中管理的所有内存资源。 例如:
-
实现固定函数管道的顶点着色器微代码可以驻留在 GPU 地址空间中,但在 VidMm 管理的内存之外(即不是段的一部分)。 此配置是可能的,因为微代码始终可用于所有进程,并且永远不会成为进程之间争用的来源。
-
对于顶点缓冲区、纹理、呈现目标和应用程序特定的着色器代码等资源,VidMm 必须从驱动程序的内存段之一分配视频内存资源。 这一要求是因为资源类型必须对所有进程公平可用。
下图显示了 KMD 如何从 GPU 地址空间配置内存段的示例。
图中的数字对应于以下内存段:67
-
CPU 可访问的线性段:此段可由 CPU 访问,并组织为线性地址空间。
-
非 CPU 可访问的线性段:该段被组织为线性地址空间,但 CPU 无法访问。 它用于不需要 CPU 访问的资源。
-
只读 AGP 光圈段:此段用于对 AGP(加速图形端口)内存进行只读访问。
-
光圈段:此段用于通过 AGP 光圈访问的资源。
隐藏框表示 KMD 不向 VidMm 公开的内存段。 隐藏在 VidMm 中的视频内存不能映射到用户空间,也不能被任何特定进程独占。 这样做违反了虚拟内存的基本规则,即要求系统上运行的所有进程都可以访问所有内存。
1. 内存段的“非全覆盖”特性
(1) KMD 的自主性
仅需声明需管理的资源:KMD 在 DXGK_SEGMENTDESCRIPTOR 中定义的段 不必涵盖 GPU 所有可用内存。
示例:
- GPU 固件(如顶点着色器微代码)可驻留在 非段内存区域,由驱动直接管理。
- 硬件保留区域(如 BootROM)无需暴露给 VidMm。
VidMm 仅管理“竞争性资源”:需要被多个进程共享或公平分配的资源(如纹理、顶点缓冲区)必须通过段管理。
(2) 非段内存的典型用途
资源类型 | 是否需通过段管理 | 原因 |
---|---|---|
顶点着色器微代码 | ❌ 否 | 只读、全局共享,无进程间竞争。 |
硬件寄存器空间 | ❌ 否 | 由 KMD 独占控制,无需虚拟化。 |
纹理/顶点缓冲区 | ✅ 是 | 多进程可能竞争,需公平分配。 |
呈现目标(Render Target) | ✅ 是 | 需隔离各进程的渲染输出。 |
2. 内存段配置示例
(1) GPU 地址空间布局
下图展示了一个可能的 GPU 地址空间划分:
GPU 地址空间布局示例:
0x00000000 ┌───────────────────────┐│ 硬件保留区域 │ (非段内存,如微代码)
0x10000000 ├───────────────────────┤│ 段 1: 显存 (VRAM) │ (VidMm 管理,供纹理/缓冲区)
0x50000000 ├───────────────────────┤│ 段 2: 系统内存光圈 │ (VidMm 管理,CPU 可访问)
0x70000000 ├───────────────────────┤│ 驱动私有区域 │ (非段内存,如调试日志)
0x80000000 └───────────────────────┘
(2) KMD 的段描述符配置
// 仅声明需要 VidMm 管理的段
DXGK_SEGMENTDESCRIPTOR Segments[] = {// 显存段(供纹理/渲染目标){.BaseAddress = 0x10000000,.Size = 0x40000000, // 1GB.Flags = DXGK_SEGMENT_FLAGS_VIDEO_MEMORY,.SegmentId = 1,},// 系统内存光圈段(供 CPU 访问的资源){.BaseAddress = 0x50000000, // CPU 物理地址.Size = 0x20000000, // 512MB.Flags = DXGK_SEGMENT_FLAGS_SYSTEM_MEMORY,.SegmentId = 2,}
};
3. 设计原理与优势
(1) 灵活性
- 硬件适配自由:KMD 可根据 GPU 特性灵活保留部分内存(如固件区域),无需强制纳入 VidMm 管理。
性能优化:全局只读资源(如微代码)可永久映射,避免重复加载。
(2) 安全性
- 隔离关键资源:硬件关键区域(如寄存器)由 KMD 独占控制,防止应用程序误操作。
- 公平性保障:竞争性资源(如显存)通过 VidMm 统一分配,避免单一进程垄断。
(3) 简化驱动开发
- 减少 VidMm 负担:非竞争性资源无需复杂的虚拟化/分页机制。
- 明确职责边界:KMD 管理硬件细节,VidMm 专注多进程资源调度
4. 开发者注意事项
(1) 必须通过段管理的资源
- 任何可能被多进程共享的资源:纹理、顶点/索引缓冲区、渲染目标、计算着色器 UAV。
- 需 CPU 访问的资源:使用 DXGK_SEGMENT_FLAGS_SYSTEM_MEMORY 声明。
(2) 禁止绕过 VidMm 的操作
- 直接访问非段内存:用户模式驱动(UMD)必须通过 VidMm 分配的 GPU 虚拟地址(GPU VA)访问资源,禁止直接操作物理地址。
- 例外:仅 KMD 可访问硬件保留区域(如通过 MmMapIoSpace)。
(3) 调试支持
- ETW 日志分析:使用 GPUView 或 WPA 检查 DXGKRNL 事件,确认段分配是否正确。
- 验证工具:DirectX 调试层(Debug Layer)可检测非法内存访问。
5. 典型问题与解决方案
问题 | 原因 | 解决方案 |
---|---|---|
分配失败(STATUS_GRAPHICS_NO_VIDEO_MEMORY) | 段空间不足 | 优化资源生命周期,或增加段大小。 |
GPU 访问违例 | 误操作非段内存 | 检查 UMD 是否使用非法 GPU VA。 |
性能下降 | 频繁切换段 | 合并资源到同一段,减少上下文切换。 |
6. 总结
KMD 选择性暴露段:仅需管理多进程竞争的动态资源(如纹理),静态资源(如微代码)可保留在非段区域。
VidMm 的职责:在已注册的段内实现公平分配、虚拟化和隔离。
驱动最佳实践:
- 明确划分段与非段内存的用途。
- 禁止用户模式直接操作硬件保留区域。
通过这种设计,WDDM 在保证多进程安全性的同时,兼顾了硬件灵活性和性能优化。