window显示驱动开发—DirectX 图形内核子系统(二)
Dxgkrnl 接口
KMD 的 DriverEntry 函数调用作系统的 DxgkInitialize 函数,这会导致 Dxgkrnl 加载和初始化。
加载后, Dxgkrnl.sys 通过将 DXGKRNL_INTERFACE 结构传递给 KMD 的 DxgkDdiStartDevice 函数,为 KMD 提供指向其函数的指针。 Dxgkrnl 的函数指针具有 DxgkCb 前缀。
DXGKRNL_INTERFACE结构还包含特定显示适配器的句柄。 显示端口驱动程序生成此句柄。 KMD 每次调用 DXGKRNL_INTERFACE中的任何函数时,都会将此句柄作为参数传递。
初始化阶段:
- KMD 在 DriverEntry 中调用 DxgkInitialize,这会触发系统加载并初始化 Dxgkrnl.sys。
- Dxgkrnl.sys 是 DirectX 图形内核的核心组件,负责管理 GPU 资源调度、内存管理、显示输出等核心功能。
设备启动阶段:
- 当显示适配器被检测到时,显示端口驱动 (如 dxgkrnl.sys) 会生成一个唯一的适配器句柄。
- Dxgkrnl 通过调用 KMD 的 DxgkDdiStartDevice 函数,传递一个 DXGKRNL_INTERFACE 结构体,其中包含:
- 回调函数指针:所有 Dxgkrnl 提供给 KMD 的接口函数均以 DxgkCb 前缀标识(例如 DxgkCbMapMemory)。
- 适配器句柄:用于唯一标识当前显示适配器的上下文。
交互机制
KMD 需要调用 Dxgkrnl 的功能时,必须通过 DXGKRNL_INTERFACE 中的函数指针进行。
每次调用时,KMD 必须传递适配器句柄作为首个参数,例如:
DXGKRNL_INTERFACE* pDxgkInterface;
pDxgkInterface->DxgkCbAllocateContiguousMemory(hAdapter, ...);
该句柄使得 Dxgkrnl 能正确路由请求到对应的 GPU 实例(在多 GPU 系统中尤为重要)。
关键数据结构
typedef struct _DXGKRNL_INTERFACE {HANDLE hAdapter; // 显示适配器句柄DXGKCB_* pDxgkCb; // 函数指针表,例如:// - DxgkCbGetDeviceInformation// - DxgkCbMapMemory// - DxgkCbSubmitCommand// ... 其他版本/上下文字段
} DXGKRNL_INTERFACE;
安全与同步
- 所有 DxgkCb 调用都运行在 PASSIVE_LEVEL 或 DISPATCH_LEVEL IRQL。
- KMD 必须确保句柄的有效性,非法句柄会导致系统蓝屏 (Bug Check)。
典型调用场景
- 内存管理:通过 DxgkCbAllocateContiguousMemory 申请 GPU 可见内存。
- 命令提交:使用 DxgkCbSubmitCommand 推送 GPU 指令队列。
- 中断处理:调用 DxgkCbNotifyInterrupt 通知显示事件。
这种设计实现了以下目标:
- 模块解耦:KMD 无需静态链接 DXGKRNL 的函数。
- 多 GPU 支持:通过句柄区分不同适配器。
- 版本兼容性:接口结构体可扩展新功能而不破坏二进制兼容性。
开发 KMD 时需注意:
- 永远不要缓存 DXGKRNL_INTERFACE 指针,应在每次需要时从上下文获取。
- 适配器句柄的生命周期由系统管理,驱动不应尝试修改或释放它。
- 所有回调函数都是线程安全的,但某些操作可能需要持有适当的锁。