Windows 图形显示驱动开发-WDDM 2.0功能_上下文监视

发布于:2025-04-12 ⋅ 阅读:(28) ⋅ 点赞:(0)

功能概述

上下文监视机制是GPU与CPU协同计算的核心同步技术,通过受监视围栏(Monitored Fence)实现跨硬件单元的高效协调。其核心目标是解决以下场景的同步需求:

  • GPU引擎间同步:例如在多渲染管线中,后处理阶段需等待前级计算完成。
  • CPU-GPU异构同步:如CPU需确保GPU完成纹理上传后再进行后续逻辑处理。
  • 跨设备资源访问:在异构计算集群中,避免多个GPU或CPU核心对共享资源的读写冲突。

传统信号量机制存在内核态切换开销大、灵活性不足等问题,而受监视围栏通过以下创新实现优化:

  • 硬件级原子操作:直接通过GPU/CPU虚拟地址读写围栏值,减少软件层干预。
  • 分离式地址映射:为CPU和GPU提供独立的内存视图,兼顾安全性与性能。
  • 自适应环绕处理:针对32位原子操作硬件自动管理围栏值溢出,降低开发者负担。 

受监视围栏的创建

创建流程与技术细节

1. 触发条件

  • Direct3D运行时检测到应用程序调用CreateFence API时,生成D3DDDI_MONITORED_FENCE类型的请求。
  • 用户模式驱动程序(UMD)通过CreateSynchronizationObjectCb回调接收创建指令。

2. 参数定义

  • 初始值(InitialValue):通常设为0,表示围栏初始未触发状态。在环形缓冲区场景中可预设为历史最大值以规避环绕问题。
  • 标志位(Flags):
  1. D3DDDI_FENCE_FLAG_SHARED:允许跨进程共享围栏对象。
  2. D3DDDI_FENCE_FLAG_CPU_WRITABLE:启用CPU直接写权限(需硬件支持MMIO)。
  3. D3DDDI_FENCE_FLAG_GLOBAL_TIMEOUT:设置全局等待超时阈值(默认禁用)。

3.内核资源分配

图形内核完成以下操作:

  • 在非分页内存池分配同步对象控制块(Sync Control Block, SCB),存储围栏状态机信息。
  • 建立双重地址映射:
  1. CPU端映射:将物理地址转换为FenceValueCPUVirtualAddress,属性为MEMORY_CACHED_TYPE_WRITEBACK,确保CPU读取时可通过缓存加速
  2. GPU端映射:若硬件支持Reserved Virtual Address (RVA),则分配固定GPU虚拟地址FenceValueGPUVirtualAddress,否则使用PCI BAR空间映射。
  • 初始化围栏监控线程,该线程以10μs周期轮询高优先级围栏对象(可通过注册表调整间隔)。

4.返回值结构

字段 技术规格
hSyncObject 64位内核对象句柄,包含版本号(高16位)和对象ID(低48位),有效周期与设备绑定。
FenceValueCPUVirtualAddress 对齐至64字节缓存行,避免False Sharing。支持通过CLFLUSH指令手动刷新缓存。
FenceValueGPUVirtualAddress 对于NVIDIA Ampere架构,强制使用Non-Coherent内存属性以兼容L2 TCC缓存策略。

原子操作兼容性处理

当GPU声明DXGK_VIDSCHCAPS::No64BitAtomics=1时,系统启用兼容模式:

  • 将64位围栏拆分为两个32位寄存器(高32位为周期计数器,低32位为递增值)。
  • 每次信号操作自动执行:
if (Low32 == UINT32_MAX) {  
    High32++;  
    Low32 = 0;  
} else {  
    Low32++;  
}  
  • 等待逻辑改为:TargetValue ≤ (High32 << 32) | Low32
  • 约束条件:TargetValue - LastSignaledValue < UINT32_MAX/2,防止高32位计数器溢出误判。

GPU信号机制

硬件信号路径

支持原子写入的GPU可直接生成以下机器指令:

; AMD GCN 示例  
global_atomic_add_x2 v[FenceValueGPUVirtualAddress], v[signal_value]  
s_waitcnt lgkmcnt(0)  

此操作在GPU L1缓存中完成,约消耗40个时钟周期。

软件信号路径


当GPU无法直接访问围栏地址(如旧式移动GPU),UMD需构造信号包:

  • 在命令缓冲区插入NOP占位符,预留12字节空间。

  • 调用SignalSynchronizationObjectFromGpuCb,内核将填充以下微代码:
0xCAFEBABE  // 魔数标识信号包  
FenceObjectID  
SignalValue  
  • GPU调度器执行到该包时,通过PM4引擎间接更新围栏值,增加约200ns延迟。

内核监控流程

  • 每个GPU上下文维护一个PendingFenceList,记录未完成的围栏信号。
  • 调度器在提交命令缓冲区前,执行以下操作:
  1. 将当前时间戳写入围栏值的Bit 63-62(保留位),用于死锁检测。
  2. 使用红黑树按信号值排序,优化遍历效率。
  • 完成事件触发后,内核工作者线程:
  1. 锁定围栏对象的自旋锁(SpinLock)。
  2. 对比当前值与等待队列中的目标阈值。
  3. 对满足条件的等待项,调用KeSetEvent唤醒相关线程。

GPU等待操作

精细化依赖管理

1.多级等待链

例如:
UMD可提交嵌套等待指令

// 等待FenceA≥100 且 FenceB≥200  
pfnWaitForSynchronizationObjectFromGpuCb(hFenceA, 100, D3DDDI_WAIT_FLAG_AND);  
pfnWaitForSynchronizationObjectFromGpuCb(hFenceB, 200, D3DDDI_WAIT_FLAG_AND);  

内核将其转换为依赖图节点,确保所有条件满足后才调度后续任务。

2.超时处理


若等待超过500ms(可配置),内核触发Timeout Workflow:

  • 生成WER错误报告,包含当前所有围栏状态快照。
  • 强制推进围栏值至目标值,标记设备为"丢失"状态。
  • 向UMD返回STATUS_GRAPHICS_DRIVER_THREAD_REQUEST_TIMEOUT错误码。 

网站公告

今日签到

点亮在社区的每一天
去签到