window显示驱动开发—多平面覆盖 VidPN 呈现

发布于:2025-08-14 ⋅ 阅读:(16) ⋅ 点赞:(0)

使用多平面覆盖时,这些要求适用于用于在视频呈现网络 (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调用处理

sequenceDiagram
    UMD->>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

 


网站公告

今日签到

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