window显示驱动开发—UMD 实现的 MPO 函数
本部分包含 WDDM 1.3 及更高版本的 UMD 必须实现的函数才能支持 MPO。
- Direct3D:UMD 通过调用 UMD 的 CreateDevice 函数中的D3DDDI_DEVICEFUNCS结构的成员提供指向 D3D MPO 函数的指针。
- DXGI:当调用特定于适配器的 CreateDevice(D3D10)函数时,UMD 通过DXGI1_3_DDI_BASE_FUNCTIONS结构的成员提供指向 DXGI MPO 函数的指针。
下表列出了 UMD 为了支持 MPO 而必须实现的函数。
下表列出了 UMD 可以选择实现的 DXGI DDI 函数。
1. Direct3D 部分 MPO 函数实现
1.1 通过 D3DDDI_DEVICEFUNCS 结构体暴露
在 CreateDevice 调用中,UMD 必须填充以下 MPO 相关函数指针:
typedef struct _D3DDDI_DEVICEFUNCS { // ... 标准 D3D 函数 ... // MPO 专用函数 (WDDM 1.3+) PFND3DDDI_CREATEOVERLAY pfnCreateOverlay; PFND3DDDI_UPDATEOVERLAY pfnUpdateOverlay; PFND3DDDI_FLIPOVERLAY pfnFlipOverlay; PFND3DDDI_DESTROYOVERLAY pfnDestroyOverlay; PFND3DDDI_GETOVERLAYCOLORCONTROLS pfnGetOverlayColorControls; PFND3DDDI_SETOVERLAYCOLORCONTROLS pfnSetOverlayColorControls;} D3DDDI_DEVICEFUNCS;
关键函数实现示例
1. pfnCreateOverlay
HRESULT APIENTRY CreateOverlay( D3DDDIARG_CREATEOVERLAY* pCreateData){ // 验证硬件支持 if (!(pDevice->Caps.OverlayCaps & D3DDDI_OVERLAY_CAPS_HW)) return E_INVALIDARG; // 分配 MPO 平面资源 MPO_PLANE* pPlane = AllocateMpoPlane(pCreateData->VideoDesc); pCreateData->hOverlay = (HANDLE)pPlane; return S_OK;}
2. pfnUpdateOverlay
HRESULT APIENTRY UpdateOverlay( D3DDDIARG_UPDATEOVERLAY* pUpdateData){ MPO_PLANE* pPlane = (MPO_PLANE*)pUpdateData->hOverlay; // 硬件原子更新 HW_MPO_UPDATE update = { .SrcRect = pUpdateData->SrcRect, .DstRect = pUpdateData->DstRect, .Rotation = pUpdateData->Rotation }; return HwUpdateMpoPlane(pPlane->hHwPlane, &update);}
2. DXGI 部分 MPO 函数实现
2.1 通过 DXGI1_3_DDI_BASE_FUNCTIONS 结构体暴露
在 DXGI 设备创建时提供以下函数指针:
typedef struct DXGI1_3_DDI_BASE_FUNCTIONS { // ... 基础 DXGI 函数 ... // MPO 扩展函数 PFNDDXGI_DDI_PRESENT_MULTIPLANE_OVERLAY pfnPresentMultiplaneOverlay; PFNDDXGI_DDI_GET_MULTIPLANE_OVERLAY_CAPS pfnGetMultiplaneOverlayCaps; PFNDDXGI_DDI_CHECK_MULTIPLANE_OVERLAY_SUPPORT pfnCheckMultiplaneOverlaySupport;} DXGI1_3_DDI_BASE_FUNCTIONS;
关键函数实现示例
1. pfnPresentMultiplaneOverlay
HRESULT APIENTRY PresentMultiplaneOverlay( DXGI_DDI_ARG_PRESENT_MULTIPLANE_OVERLAY* pPresentData){ // 验证每个平面 for (UINT i = 0; i NumPlanes; i++) { if (!ValidatePlane(pPresentData->pPlanes[i])) return DXGI_DDI_ERR_INVALID_CALL; } // 硬件提交 return HwPresentMpo(pPresentData->pPlanes, pPresentData->NumPlanes);}
2. pfnGetMultiplaneOverlayCaps
HRESULT APIENTRY GetMultiplaneOverlayCaps( DXGI_DDI_ARG_GET_MULTIPLANE_OVERLAY_CAPS* pCapsData){ pCapsData->Caps = { .MaxPlanes = 4, // 硬件支持的最大平面数 .SupportsRGB = TRUE, // 支持 RGB 平面 .SupportsYCbCr = TRUE, // 支持 YUV 平面 .SupportsRotation = TRUE // 支持硬件旋转 }; return S_OK;}
3. MPO 功能验证流程
3.1 初始化阶段检查
sequenceDiagram UMD->>KMD: GetCaps(D3DDDICAPS_GETD3D9CAPS) KMD-->>UMD: 返回D3DCAPS_OVERLAY标志 UMD->>KMD: QueryInterface(DXGI1_3_DDI) KMD-->>UMD: 提供DXGI MPO函数表
3.2 运行时状态管理
// MPO 平面状态机typedef enum { MPO_STATE_FREE, // 未分配 MPO_STATE_ACTIVE, // 正在显示 MPO_STATE_PENDING, // 等待VSync} MPO_PLANE_STATE;
4. WHQL 认证必备实现
5. 错误处理规范
DXGI_DDI_ERR_UNSUPPORTED
DXGI_DDI_ERR_INVALID_CALL
E_ACCESSDENIED
6. 性能优化技巧
6.1 平面重用池
class MpoPlanePool { std::vector m_freePlanes;public: MPO_PLANE_CTX* AllocatePlane(DXGI_FORMAT fmt) { // 从池中获取或新建平面 }};
6.2 硬件特性利用
- Intel:使用 Plane Rotation 减少内存拷贝
- NVIDIA:通过 Overlay Plane 降低视频播放功耗
- AMD:结合 FreeSync 实现动态刷新率同步
7. 调试与验证工具
DirectX 控制面板:
dxcpl.exe -> MPO 诊断选项卡
ETW 追踪:
logman start MPOTrace -p Microsoft-Windows-DXG-Kernel 0xFFFF -o trace.etl
硬件寄存器检查:
// 读取显示控制器状态UINT regVal = ReadHwRegister(DISPLAY_ENGINE_MPO_STATUS);
8. 向后兼容性处理
#if (D3D_UMD_INTERFACE_VERSION >= D3D_UMD_INTERFACE_VERSION_WINBLUE) // 完整实现 WDDM 1.3 MPO 函数#else // 返回 E_NOTIMPL 并记录警告 DbgPrint(\"MPO requires WDDM 1.3+\\n\");#endif