window显示驱动开发—多平面覆盖 VidPN 呈现
使用多平面覆盖时,这些要求适用于用于在视频呈现网络 (VidPNs) 的多个表面上显示的功能:
DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay
- 如果 DXGK_MULTIPLANE_OVERLAY_PLANE。Enabled 为 false,显示微型端口驱动程序应禁用指定的平面。
- 如果在上一次调用 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay 时启用了平面,但当前调用中不存在某个平面,则驱动程序应继续显示平面而不翻转平面。
- 在同一 VSync 期间,驱动程序可能会收到对 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay 的多个调用, (一个调用翻转一个平面,另一个调用) 翻转其他平面。 在这种情况下,驱动程序应处理这两个调用。
- 传递的数据应在用户模式下由受信任的源进行验证。 但是,显示微型端口驱动程序仍应检查数据,以确保它不会导致问题。 如果数据不正确,驱动程序可能会使调用失败并 出现STATUS_INVALID_PARAMETER 错误代码,但此类故障可能无法正常处理,并且意味着操作系统或用户模式驱动程序中存在 bug。
DxgkDdiSetVidPnSourceVisibility
DXGKARG_SETVIDPNSOURCEVISIBILITY时。在调用此函数时,在给定源上,Visible 设置为 FALSE,必须禁用所有硬件平面,包括用于主表面的层。 当 Visible 设置为 TRUE 时,必须仅启用用于主图面的平面,并且所有其他平面必须保持禁用状态。
DxgkDdiSetVidPnSourceAddress
调用此函数时,驱动程序应禁用所有非主覆盖平面。 在多平面覆盖模式下,主图面使用 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay 翻转。
1. DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay 实现规范
1.1 平面启用/禁用控制
NTSTATUS APIENTRY DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay(_In_ const DXGKARG_SETVIDPNSOURCEADDRESSWITHMULTIPLANEOVERLAY* pArgs)
{// 处理每个平面for (UINT i = 0; i < pArgs->PlaneCount; i++) {const DXGK_MULTIPLANE_OVERLAY_PLANE* pPlane = &pArgs->PlaneList[i];if (!pPlane->Enabled) {// 禁用指定平面DisableHwPlane(pPlane->PlaneId);} else {// 配置平面属性ProgramPlaneAttributes(pPlane);}}// 处理未包含但之前启用的平面for (UINT id : g_ActivePlanes) {if (!IsPlaneInCurrentRequest(id, pArgs)) {// 保持显示但不翻转内容MaintainPlaneWithoutFlip(id);}}return STATUS_SUCCESS;
}
1.2 多VSync调用处理
sequenceDiagramUMD->>KMD: SetVidPnSourceAddress(PlaneA Flip)KMD->>Hardware: 更新PlaneA缓冲区UMD->>KMD: SetVidPnSourceAddress(PlaneB Flip)KMD->>Hardware: 更新PlaneB缓冲区Hardware-->>Display: 同一VSync周期内提交AB平面
关键要求:
- 必须支持同一VSync周期内的多次调用
- 各平面更新需原子化提交
2. 可见性控制函数
2.1 DxgkDdiSetVidPnSourceVisibility 实现
NTSTATUS APIENTRY DxgkDdiSetVidPnSourceVisibility(_In_ const DXGKARG_SETVIDPNSOURCEVISIBILITY* pArgs)
{if (!pArgs->Visible) {// 禁用所有平面(包括主平面)for (UINT i = 0; i < MAX_PLANES; i++) {DisableHwPlane(i);}} else {// 仅启用主平面EnablePrimaryPlane(pArgs->VidPnSourceId);// 保持其他平面禁用for (UINT i = 1; i < MAX_PLANES; i++) {DisableHwPlane(i);}}return STATUS_SUCCESS;
}
2.2 状态转换规则
当前状态 | 新Visible值 | 操作要求 |
---|---|---|
全部启用 | FALSE | 立即禁用所有平面 |
部分启用 | FALSE | 禁用剩余平面 |
全部禁用 | TRUE | 仅启用主平面 |
主平面启用 | TRUE | 无操作(维持状态) |
3. 传统模式兼容性
3.1 DxgkDdiSetVidPnSourceAddress 行为
NTSTATUS APIENTRY DxgkDdiSetVidPnSourceAddress(_In_ const DXGKARG_SETVIDPNSOURCEADDRESS* pArgs)
{// 在非MPO模式下禁用所有叠加平面if (!IsInMpoMode()) {for (UINT i = 1; i < MAX_PLANES; i++) {DisableHwPlane(i);}}// 标准处理流程return OriginalSetVidPnSourceAddress(pArgs);
}
向后兼容要求:
- 必须保持与非MPO显示模式的兼容性
- 在传统模式下自动禁用叠加平面
4. 安全验证与错误处理
4.1 参数验证清单
BOOL ValidateMpoParams(const DXGKARG_SETVIDPNSOURCEADDRESSWITHMULTIPLANEOVERLAY* pArgs)
{// 基础检查if (pArgs->VidPnSourceId >= MAX_SOURCES || pArgs->PlaneCount > MAX_PLANES) {return FALSE;}// 平面属性验证for (UINT i = 0; i < pArgs->PlaneCount; i++) {const DXGK_MULTIPLANE_OVERLAY_PLANE* pPlane = &pArgs->PlaneList[i];if (pPlane->PlaneId >= MAX_PLANES ||!ValidateRect(&pPlane->SrcRect) ||!ValidateRect(&pPlane->DstRect)) {return FALSE;}}return TRUE;
}
4.2 错误处理规范
错误类型 | 处理方式 |
---|---|
无效VidPnSourceId | 返回STATUS_GRAPHICS_INVALID_VIDPN_SOURCEID |
非法矩形坐标 | 返回STATUS_INVALID_PARAMETER |
硬件资源冲突 | 返回STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE |
5. 性能优化建议
5.1 平面状态缓存
typedef struct _PLANE_STATE_CACHE {BOOL Enabled;RECT SrcRect;RECT DstRect;FLOAT Alpha;
} PLANE_STATE_CACHE;// 全局缓存数组
PLANE_STATE_CACHE g_PlaneCache[MAX_PLANES];
5.2 差异更新机制
void SmartPlaneUpdate(UINT PlaneId, const DXGK_MULTIPLANE_OVERLAY_PLANE* pNewState)
{if (memcmp(&g_PlaneCache[PlaneId], pNewState, sizeof(PLANE_STATE_CACHE)) != 0) {// 仅当状态变化时更新硬件ProgramHwPlane(PlaneId, pNewState);g_PlaneCache[PlaneId] = *pNewState;}
}
6. WHQL 认证要求
6.1 必须通过的测试
Device.Graphics.WDDM.MPO.Visibility
- 验证Visible=FALSE时的平面禁用
- 测试主平面独占模式
Device.Graphics.WDDM.MPO.LegacyCompatibility
- 传统SetVidPnSourceAddress调用时的行为
6.2 认证检查清单
- 正确处理Enabled=false的平面
- 实现VSync周期内的多调用支持
- 完备的参数验证逻辑
- 与传统模式的正确交互
7. 调试与诊断
7.1 注册表调试键
Windows Registry Editor Version 5.00[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WSD]
"LogMpoVisibilityChanges"=dword:00000001
"MpoParamValidationLevel"=dword:00000002
7.2 事件日志分析
# 查看MPO可见性变更记录
Get-WinEvent -ProviderName Microsoft-Windows-Win32k |
Where-Object {$_.Id -eq 300} |
Format-Table -Property TimeCreated, Message