ReactOS 图形系统分析(9):物理设备对象 — PDEVOBJ

ReactOS 图形系统分析(9):物理设备对象 --- PDEVOBJ

1. 概述

PDEVOBJ(物理设备对象,Physical Device Object)位于 win32ss/gdi/eng/pdevobj.c(实现)与 pdevobj.h(定义),是 GDI 引擎中代表一个物理显示/打印设备的核心对象。它绑定"逻辑设备(LDEV)的 DDI 函数表"与"具体显示驱动实例(DHPDEV)",管理设备表面、调色板、DEVMODE、加速等级等全部设备状态。

复制代码
GRAPHICS_DEVICE (图形设备:设备名/DEVICEMAP 映射)
   ↓ PDEVOBJ_Create
PDEVOBJ (物理设备对象 ← 本分析对象)
   ├── pldev → LDEVOBJ (驱动加载 + DDI 函数表)
   ├── dhpdev → 驱动实例句柄 (DrvEnablePDEV 返回)
   ├── pSurface → 显示表面 (DrvEnableSurface 创建)
   ├── devinfo / gdiinfo → 设备能力
   └── pfn → DRIVER_FUNCTIONS (DDI 回调表副本)

在引擎渲染时,SURFOBJ->hdev 实际就是 PDEVOBJ 指针,GDIDEVFUNCS(pso) 宏从 PDEVOBJ 取 DDI 函数表------因此 PDEVOBJ 是引擎调度显示驱动的枢纽


2. 核心数据结构 --- PDEVOBJ(pdevobj.h(file:///d:/reactos/win32ss/gdi/eng/pdevobj.h#L79-L149))

c 复制代码
typedef struct _PDEVOBJ
{
    BASEOBJECT                BaseObject;
    struct _PDEVOBJ *         ppdevNext;        // 全局 PDEV 链表
    LONG                      cPdevRefs;        // 引用计数
    LONG                      cPdevOpenRefs;
    struct _PDEVOBJ *         ppdevParent;      // 父 PDEV(克隆)
    FLONG                     flFlags;          // PDEV_* 标志
    HSEMAPHORE                hsemDevLock;      // 设备锁
    POINTL                    ptlPointer;       // 指针位置
    HSURF                     ahsurf[HS_DDI_MAX]; // 引擎图案表面句柄数组
    PWSTR                     pusPrtDataFileName;  // 打印机数据文件
    ULONG                     cDirectDrawDisableLocks;
    PVOID                     pvGammaRamp;      // Gamma 曲线
    SIZEL                     szlMetaRes;       // 元文件设备分辨率
    PFN_DrvMovePointer        pfnMovePointer;   // 指针移动函数(默认为 EngMovePointer)
    struct _LDEVOBJ *         pldev;            // ← 逻辑设备对象
    DHPDEV                    dhpdev;           // ← 驱动设备句柄
    struct _PALETTE*          ppalSurf;         // 设备调色板
    DEVINFO                   devinfo;          // ← 设备信息(DrvEnablePDEV 填)
    GDIINFO                   gdiinfo;          // ← GDI 信息(DrvEnablePDEV 填)
    PSURFACE                  pSurface;         // ← 显示表面
    HANDLE                    hSpooler;         // 设备对象(图形设备)
    PGRAPHICS_DEVICE          pGraphicsDevice;  // ← 图形设备
    POINTL                    ptlOrigion;
    PDEVMODEW                 pdmwDev;          // 当前 DEVMODE
    FLONG                     DxDd_Flags;       // DirectDraw 状态
    DWORD                     dwAccelerationLevel; // ← 加速等级 (0-5)
    union
    {
      DRIVER_FUNCTIONS        DriverFunctions;  // ← DDI 函数表副本
      PVOID                   apfn[INDEX_LAST];
    };
    GDIPOINTER                Pointer;          // 软件光标状态
    struct _EDD_DIRECTDRAW_GLOBAL * pEDDgpl;    // DirectDraw 全局
} PDEVOBJ, *PPDEVOBJ;

2.1 PDEV 标志(flFlags

标志 含义
PDEV_DISPLAY 显示设备
PDEV_HARDWARE_POINTER / PDEV_SOFTWARE_POINTER 硬件/软件光标
PDEV_GOTFONTS 已加载字体驱动
PDEV_PRINTER 打印设备
PDEV_DISABLED 设备已禁用
PDEV_SYNCHRONIZE_ENABLED 同步已启用
PDEV_FONTDRIVER 字体设备
PDEV_UMPD 用户模式驱动
PDEV_META_DEVICE 元文件设备
PDEV_CLONE_DEVICE 克隆设备

2.2 相关结构

GDIPOINTER --- 软件光标状态:

c 复制代码
typedef struct _GDIPOINTER
{
  BOOL     Enabled;      // 是否启用
  SIZEL    Size;         // 光标尺寸
  POINTL   HotSpot;      // 热点
  SURFACE  *psurfColor;  // 颜色表面
  SURFACE  *psurfMask;   // 掩码表面
  SURFACE  *psurfSave;   // 保存表面(光标下像素)
  FLONG    flags;
  RECTL    Exclude;      // 排除区域
} GDIPOINTER, *PGDIPOINTER;

GRAPHICS_DEVICE --- 图形设备(每个显示设备一份):

c 复制代码
typedef struct _GRAPHICS_DEVICE
{
    WCHAR szNtDeviceName[CCHDEVICENAME/2];   // NT 设备名 (\Device\Video0)
    WCHAR szWinDeviceName[CCHDEVICENAME/2];  // Win32 设备名 (DISPLAY1)
    PDEVICE_OBJECT DeviceObject;             // 设备对象
    DWORD StateFlags;                        // DISPLAY_DEVICE_*
    PDEVMODEINFO pdevmodeInfo;               // DEVMODE 链表
    ULONG cDevModes;
    LPWSTR pDiplayDrivers;                   // InstalledDisplayDrivers
    LPWSTR pwszDescription;                  // 设备描述
} GRAPHICS_DEVICE, *PGRAPHICS_DEVICE;

3. 生命周期管理

3.1 分配 / 引用 / 释放

c 复制代码
PPDEVOBJ PDEVOBJ_AllocPDEV(VOID)
{
    ppdev = ExAllocatePoolWithTag(PagedPool, sizeof(PDEVOBJ), GDITAG_PDEV);
    RtlZeroMemory(ppdev, sizeof(PDEVOBJ));
    ppdev->hsemDevLock = EngCreateSemaphore();      // 设备锁
    ppdev->pEDDgpl = ExAllocatePoolWithTag(...);    // DirectDraw 全局
    ppdev->cPdevRefs = 1;                           // 初始引用
    return ppdev;
}

/* 引用:正在销毁的 PDEV 拒绝引用 */
FORCEINLINE VOID PDEVOBJ_vReference(PPDEVOBJ ppdev)
{
    if (ppdev->cPdevRefs == 0) { ASSERT(FALSE); return; }
    InterlockedIncrement(&ppdev->cPdevRefs);
}

/* 释放:计数归零时销毁表面、调色板并删除 PDEV */
VOID PDEVOBJ_vRelease(PPDEVOBJ ppdev)
{
    if (InterlockedDecrement(&ppdev->cPdevRefs) == 0)
    {
        if (ppdev->pSurface)         /* 调 DrvDisableSurface */
        {
            SURFACE_ShareUnlockSurface(ppdev->pSurface);
            ppdev->pfn.DisableSurface(ppdev->dhpdev);
        }
        if (ppdev->ppalSurf)          /* 释放调色板 */
            PALETTE_ShareUnlockPalette(ppdev->ppalSurf);
        if (ppdev->pfn.DisablePDEV)   /* 调 DrvDisablePDEV */
            ppdev->pfn.DisablePDEV(ppdev->dhpdev);
        PDEVOBJ_vDeletePDEV(ppdev);   /* 释放 DEVMODE/锁/对象 */
    }
}

全局链表: gppdevList(受 ghsemPDEV 信号量保护)串联所有 PDEV;InitPDEVImpl 在 win32k 初始化时创建信号量。


4. PDEVOBJ_Create --- 设备创建核心

#mermaid-svg-chMJEYbpnpo1qsDU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-chMJEYbpnpo1qsDU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-chMJEYbpnpo1qsDU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-chMJEYbpnpo1qsDU .error-icon{fill:#552222;}#mermaid-svg-chMJEYbpnpo1qsDU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-chMJEYbpnpo1qsDU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-chMJEYbpnpo1qsDU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-chMJEYbpnpo1qsDU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-chMJEYbpnpo1qsDU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-chMJEYbpnpo1qsDU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-chMJEYbpnpo1qsDU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-chMJEYbpnpo1qsDU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-chMJEYbpnpo1qsDU .marker.cross{stroke:#333333;}#mermaid-svg-chMJEYbpnpo1qsDU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-chMJEYbpnpo1qsDU p{margin:0;}#mermaid-svg-chMJEYbpnpo1qsDU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-chMJEYbpnpo1qsDU .cluster-label text{fill:#333;}#mermaid-svg-chMJEYbpnpo1qsDU .cluster-label span{color:#333;}#mermaid-svg-chMJEYbpnpo1qsDU .cluster-label span p{background-color:transparent;}#mermaid-svg-chMJEYbpnpo1qsDU .label text,#mermaid-svg-chMJEYbpnpo1qsDU span{fill:#333;color:#333;}#mermaid-svg-chMJEYbpnpo1qsDU .node rect,#mermaid-svg-chMJEYbpnpo1qsDU .node circle,#mermaid-svg-chMJEYbpnpo1qsDU .node ellipse,#mermaid-svg-chMJEYbpnpo1qsDU .node polygon,#mermaid-svg-chMJEYbpnpo1qsDU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-chMJEYbpnpo1qsDU .rough-node .label text,#mermaid-svg-chMJEYbpnpo1qsDU .node .label text,#mermaid-svg-chMJEYbpnpo1qsDU .image-shape .label,#mermaid-svg-chMJEYbpnpo1qsDU .icon-shape .label{text-anchor:middle;}#mermaid-svg-chMJEYbpnpo1qsDU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-chMJEYbpnpo1qsDU .rough-node .label,#mermaid-svg-chMJEYbpnpo1qsDU .node .label,#mermaid-svg-chMJEYbpnpo1qsDU .image-shape .label,#mermaid-svg-chMJEYbpnpo1qsDU .icon-shape .label{text-align:center;}#mermaid-svg-chMJEYbpnpo1qsDU .node.clickable{cursor:pointer;}#mermaid-svg-chMJEYbpnpo1qsDU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-chMJEYbpnpo1qsDU .arrowheadPath{fill:#333333;}#mermaid-svg-chMJEYbpnpo1qsDU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-chMJEYbpnpo1qsDU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-chMJEYbpnpo1qsDU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-chMJEYbpnpo1qsDU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-chMJEYbpnpo1qsDU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-chMJEYbpnpo1qsDU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-chMJEYbpnpo1qsDU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-chMJEYbpnpo1qsDU .cluster text{fill:#333;}#mermaid-svg-chMJEYbpnpo1qsDU .cluster span{color:#333;}#mermaid-svg-chMJEYbpnpo1qsDU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-chMJEYbpnpo1qsDU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-chMJEYbpnpo1qsDU rect.text{fill:none;stroke-width:0;}#mermaid-svg-chMJEYbpnpo1qsDU .icon-shape,#mermaid-svg-chMJEYbpnpo1qsDU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-chMJEYbpnpo1qsDU .icon-shape p,#mermaid-svg-chMJEYbpnpo1qsDU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-chMJEYbpnpo1qsDU .icon-shape .label rect,#mermaid-svg-chMJEYbpnpo1qsDU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-chMJEYbpnpo1qsDU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-chMJEYbpnpo1qsDU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-chMJEYbpnpo1qsDU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是



失败


失败
失败
PDEVOBJ_Create

(pGraphicsDevice, pdm,

dwAccelerationLevel, ldevtype)
非 META 设备?
遍历 gppdevList 查找匹配

(同 GraphicsDevice + 同 DEVMODE

  • 同加速等级)
    找到匹配 PDEV?
    PDEVOBJ_vEnableDisplay

重新启用后返回(复用)
PDEVOBJ_bDisableDisplay

(关闭不匹配的旧 PDEV)
LDEVOBJ_pLoadInternal

(元文件内部驱动)
LDEVOBJ_pLoadDriver

(加载显示驱动)
返回 NULL
PDEVOBJ_AllocPDEV 分配
保存 GraphicsDevice/hSpooler

复制 DEVMODE
flFlags = PDEV_DISPLAY

指针排除区初始化
复制 DDI 函数表

pfn = pldev->pfn
加速等级≥5 或需平移?
用 gPanDispDrvFn 覆盖

平移显示函数表
保持原函数表
PDEVOBJ_bEnablePDEV

→ DrvEnablePDEV
PDEVOBJ_vCompletePDEV

→ DrvCompletePDEV
PDEVOBJ_pSurface

→ DrvEnableSurface 创建表面
PDEVOBJ_bEnableDirectDraw
PDEVOBJ_vFilterDriverHooks

(按加速等级过滤 DDI)
设置 pfnMovePointer

(无驱动实现则 EngMovePointer)
插入 gppdevList 链表
返回 ppdev

关键点:

  • PDEV 复用:相同设备 + 相同模式 + 相同加速等级的 PDEV 直接复用,避免重复创建
  • 平移显示(Panning) :加速等级 ≥5 或请求平移模式时,用 gPanDispDrvFn 覆盖部分 DDI 函数表实现平移显示
  • 创建失败回滚 :任一步失败即 PDEVOBJ_vRelease + EngUnloadImage 释放驱动

4.1 PDEVOBJ_bEnablePDEV --- 调用 DrvEnablePDEV

c 复制代码
BOOL NTAPI PDEVOBJ_bEnablePDEV(PPDEVOBJ ppdev, PDEVMODEW pdevmode, PWSTR pwszLogAddress)
{
    pfnEnablePDEV = ppdev->pfn.EnablePDEV;

    /* 调用驱动 DrvEnablePDEV,驱动填充 gdiinfo/devinfo 并返回 dhpdev */
    ppdev->dhpdev = pfnEnablePDEV(pdevmode, pwszLogAddress,
                                  HS_DDI_MAX, ppdev->ahsurf,     // 图案表面数组
                                  sizeof(GDIINFO), (PULONG)&ppdev->gdiinfo,
                                  sizeof(DEVINFO), &ppdev->devinfo,
                                  (HDEV)ppdev,                    // hdev = PDEVOBJ!
                                  pwszDescription, DeviceObject);
    if (ppdev->dhpdev == NULL) return FALSE;

    /* 修正缺失值 */
    if (ppdev->gdiinfo.ulLogPixelsX == 0) ppdev->gdiinfo.ulLogPixelsX = 96;
    if (ppdev->gdiinfo.ulLogPixelsY == 0) ppdev->gdiinfo.ulLogPixelsY = 96;

    /* 设置光栅能力(RC_*) */
    ppdev->gdiinfo.flRaster = RC_OP_DX_OUTPUT | RC_GDI20_OUTPUT | RC_BIGFONT;
    if (非绘图仪/字符流设备)
        flRaster |= RC_STRETCHDIB | RC_STRETCHBLT | RC_DIBTODEV | RC_BITBLT ...;
    if (DT_RASDISPLAY) flRaster |= RC_FLOODFILL;
    if (GCAPS_PALMANAGED) flRaster |= RC_PALETTE;

    /* 锁定默认调色板;用引擎影线画刷补全空位 */
    ppdev->ppalSurf = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
    for (i = 0; i < HS_DDI_MAX; i++)
        if (ppdev->ahsurf[i] == NULL)
            ppdev->ahsurf[i] = gahsurfHatch[i];   // 引擎影线表面
    return TRUE;
}

要点: hdev 参数直接传入 (HDEV)ppdev------这就是为什么 SURFOBJ->hdev 能通过 GDIDEVFUNCS 取回 DDI 函数表。

4.2 加速等级过滤 --- PDEVOBJ_vFilterDriverHooks

注册表 Accelerations.Level(0~5)控制驱动加速能力:

等级 行为
≥1 移除 DrvSetPointerShape、DrvCreateDeviceBitmap
≥2 移除表面 HOOK_STRETCHBLT/FILLPATH/GRADIENTFILL/LINETO/ALPHABLEND/TRANSPARENTBLT
≥3 禁用 DirectDraw/Direct3D 加速(FIXME 未实现)
≥4 移除几乎所有 HOOK(仅保留 BITBLT/COPYBITS/TEXTOUT/STROKEPATH/SYNCHRONIZE)

5. 模式管理

5.1 PDEVOBJ_bSwitchMode --- 切换显示模式

#mermaid-svg-s9Fbp2nF2syXuBda{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-s9Fbp2nF2syXuBda .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-s9Fbp2nF2syXuBda .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-s9Fbp2nF2syXuBda .error-icon{fill:#552222;}#mermaid-svg-s9Fbp2nF2syXuBda .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-s9Fbp2nF2syXuBda .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-s9Fbp2nF2syXuBda .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-s9Fbp2nF2syXuBda .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-s9Fbp2nF2syXuBda .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-s9Fbp2nF2syXuBda .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-s9Fbp2nF2syXuBda .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-s9Fbp2nF2syXuBda .marker{fill:#333333;stroke:#333333;}#mermaid-svg-s9Fbp2nF2syXuBda .marker.cross{stroke:#333333;}#mermaid-svg-s9Fbp2nF2syXuBda svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-s9Fbp2nF2syXuBda p{margin:0;}#mermaid-svg-s9Fbp2nF2syXuBda .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-s9Fbp2nF2syXuBda .cluster-label text{fill:#333;}#mermaid-svg-s9Fbp2nF2syXuBda .cluster-label span{color:#333;}#mermaid-svg-s9Fbp2nF2syXuBda .cluster-label span p{background-color:transparent;}#mermaid-svg-s9Fbp2nF2syXuBda .label text,#mermaid-svg-s9Fbp2nF2syXuBda span{fill:#333;color:#333;}#mermaid-svg-s9Fbp2nF2syXuBda .node rect,#mermaid-svg-s9Fbp2nF2syXuBda .node circle,#mermaid-svg-s9Fbp2nF2syXuBda .node ellipse,#mermaid-svg-s9Fbp2nF2syXuBda .node polygon,#mermaid-svg-s9Fbp2nF2syXuBda .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-s9Fbp2nF2syXuBda .rough-node .label text,#mermaid-svg-s9Fbp2nF2syXuBda .node .label text,#mermaid-svg-s9Fbp2nF2syXuBda .image-shape .label,#mermaid-svg-s9Fbp2nF2syXuBda .icon-shape .label{text-anchor:middle;}#mermaid-svg-s9Fbp2nF2syXuBda .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-s9Fbp2nF2syXuBda .rough-node .label,#mermaid-svg-s9Fbp2nF2syXuBda .node .label,#mermaid-svg-s9Fbp2nF2syXuBda .image-shape .label,#mermaid-svg-s9Fbp2nF2syXuBda .icon-shape .label{text-align:center;}#mermaid-svg-s9Fbp2nF2syXuBda .node.clickable{cursor:pointer;}#mermaid-svg-s9Fbp2nF2syXuBda .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-s9Fbp2nF2syXuBda .arrowheadPath{fill:#333333;}#mermaid-svg-s9Fbp2nF2syXuBda .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-s9Fbp2nF2syXuBda .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-s9Fbp2nF2syXuBda .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-s9Fbp2nF2syXuBda .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-s9Fbp2nF2syXuBda .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-s9Fbp2nF2syXuBda .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-s9Fbp2nF2syXuBda .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-s9Fbp2nF2syXuBda .cluster text{fill:#333;}#mermaid-svg-s9Fbp2nF2syXuBda .cluster span{color:#333;}#mermaid-svg-s9Fbp2nF2syXuBda div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-s9Fbp2nF2syXuBda .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-s9Fbp2nF2syXuBda rect.text{fill:none;stroke-width:0;}#mermaid-svg-s9Fbp2nF2syXuBda .icon-shape,#mermaid-svg-s9Fbp2nF2syXuBda .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-s9Fbp2nF2syXuBda .icon-shape p,#mermaid-svg-s9Fbp2nF2syXuBda .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-s9Fbp2nF2syXuBda .icon-shape .label rect,#mermaid-svg-s9Fbp2nF2syXuBda .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-s9Fbp2nF2syXuBda .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-s9Fbp2nF2syXuBda .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-s9Fbp2nF2syXuBda :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 失败
PDEVOBJ_bSwitchMode(ppdev, pdm)
加锁

hsemDevLock + ghsemPDEV
PDEVOBJ_bDisableDisplay

临时禁用当前 PDEV
恢复 DirectDraw 后退出
PDEVOBJ_bEnablePDEV

用新模式重新启用(DrvEnablePDEV)
PDEVOBJ_pSurface

创建新表面
PDEVOBJ_bEnableDirectDraw
PDEVOBJ_bDynamicModeChange

(新旧 PDEV 交换状态)
解锁并返回

5.2 PDEVOBJ_bDynamicModeChange --- 动态模式切换

切换模式时创建临时 PDEV (新模式),然后与旧 PDEV 交换全部状态

c 复制代码
BOOL NTAPI PDEVOBJ_bDynamicModeChange(PPDEVOBJ ppdev, PPDEVOBJ ppdev2)
{
    /* 交换:DDI 函数表 / LDEV / DHPDEV / 表面 / devinfo / gdiinfo / DEVMODE / 状态标志 */
    temp.pfn = ppdev->pfn;  ppdev->pfn = ppdev2->pfn;  ppdev2->pfn = temp.pfn;
    SwitchPointer(&ppdev->pldev, &ppdev2->pldev);
    SwitchPointer(&ppdev->dhpdev, &ppdev2->dhpdev);
    SwitchPointer(&ppdev->pSurface, &ppdev2->pSurface);

    /* 表面重新关联新 PDEV */
    ppdev->pSurface->SurfObj.hdev = (HDEV)ppdev;
    ppdev2->pSurface->SurfObj.hdev = (HDEV)ppdev2;

    /* 通知驱动新的 HDEV 关联 */
    ppdev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev);
    ppdev2->pfn.CompletePDEV(ppdev2->dhpdev, (HDEV)ppdev2);

    /* 切换 DirectDraw 模式 */
    PDEVOBJ_vSwitchDirectDraw(ppdev, ppdev2);
}

优点: 无需销毁重建 PDEV,模式切换期间所有表面/句柄连续有效。


6. 与显示驱动的完整交互

显示驱动 (framebuf/vga) PDEVOBJ LDEVOBJ (加载驱动) PDEVOBJ_Create win32k 初始化 显示驱动 (framebuf/vga) PDEVOBJ LDEVOBJ (加载驱动) PDEVOBJ_Create win32k 初始化 #mermaid-svg-tLdur69NNO8pav6D{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tLdur69NNO8pav6D .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tLdur69NNO8pav6D .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tLdur69NNO8pav6D .error-icon{fill:#552222;}#mermaid-svg-tLdur69NNO8pav6D .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tLdur69NNO8pav6D .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tLdur69NNO8pav6D .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tLdur69NNO8pav6D .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tLdur69NNO8pav6D .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tLdur69NNO8pav6D .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tLdur69NNO8pav6D .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tLdur69NNO8pav6D .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tLdur69NNO8pav6D .marker.cross{stroke:#333333;}#mermaid-svg-tLdur69NNO8pav6D svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tLdur69NNO8pav6D p{margin:0;}#mermaid-svg-tLdur69NNO8pav6D .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tLdur69NNO8pav6D text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-tLdur69NNO8pav6D .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-tLdur69NNO8pav6D .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-tLdur69NNO8pav6D .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-tLdur69NNO8pav6D .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-tLdur69NNO8pav6D #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-tLdur69NNO8pav6D .sequenceNumber{fill:white;}#mermaid-svg-tLdur69NNO8pav6D #sequencenumber{fill:#333;}#mermaid-svg-tLdur69NNO8pav6D #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-tLdur69NNO8pav6D .messageText{fill:#333;stroke:none;}#mermaid-svg-tLdur69NNO8pav6D .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tLdur69NNO8pav6D .labelText,#mermaid-svg-tLdur69NNO8pav6D .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-tLdur69NNO8pav6D .loopText,#mermaid-svg-tLdur69NNO8pav6D .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-tLdur69NNO8pav6D .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-tLdur69NNO8pav6D .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-tLdur69NNO8pav6D .noteText,#mermaid-svg-tLdur69NNO8pav6D .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-tLdur69NNO8pav6D .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tLdur69NNO8pav6D .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tLdur69NNO8pav6D .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tLdur69NNO8pav6D .actorPopupMenu{position:absolute;}#mermaid-svg-tLdur69NNO8pav6D .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-tLdur69NNO8pav6D .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tLdur69NNO8pav6D .actor-man circle,#mermaid-svg-tLdur69NNO8pav6D line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-tLdur69NNO8pav6D :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 桌面就绪 创建显示 PDEV (DEVMODE) LDEVOBJ_pLoadDriver(设备名) pldev (含 DDI 函数表) PDEVOBJ_AllocPDEV DrvEnablePDEV(DEVMODE, hdev=PDEVOBJ) dhpdev + gdiinfo/devinfo DrvCompletePDEV(hdev) DrvEnableSurface → 表面 hSurfEng (ahsurf/表面句柄) 设置 pfnMovePointer / DirectDraw 返回 PDEVOBJ 渲染 → GDIDEVFUNCS(pso) 从 PDEVOBJ 取 DDI 切换模式 → PDEVOBJ_bSwitchMode 关闭显示 → PDEVOBJ_bDisableDisplay


7. 设计特点总结

  1. 设备调度枢纽 :PDEVOBJ 聚合"LDEV 函数表 + 驱动实例 dhpdev + 表面 + 设备信息",SURFOBJ->hdev == PDEVOBJ,引擎由此统一调度驱动 DDI。
  2. PDEV 复用:相同设备/模式/加速等级复用已有 PDEV,避免重复初始化。
  3. 引用计数生命周期cPdevRefs 计数保护,归零时依次释放表面(DrvDisableSurface)、调色板、PDEV(DrvDisablePDEV)。
  4. 模式切换无损PDEVOBJ_bDynamicModeChange 交换全部状态而非重建,切换期间句柄连续有效。
  5. 加速等级可调 :注册表 Accelerations.Level(0~5)逐级移除驱动加速,用于调试和兼容。
  6. 软件光标兜底pfnMovePointer 无驱动实现时回退 EngMovePointer
  7. 平移显示支持:加速等级 ≥5 时用平移函数表覆盖 DDI,支持大桌面小屏幕。
  8. 影线画刷补齐:驱动未提供的图案表面用引擎影线画刷(gahsurfHatch)补全。

8. 源码索引

位置 关键内容
pdevobj.h(file:///d:/reactos/win32ss/gdi/eng/pdevobj.h#L4-L23) PDEVFLAGS 标志定义
pdevobj.h(file:///d:/reactos/win32ss/gdi/eng/pdevobj.h#L27-L48) GDIPOINTER、DEVMODEINFO 结构
pdevobj.h(file:///d:/reactos/win32ss/gdi/eng/pdevobj.h#L57-L77) GRAPHICS_DEVICE 结构
pdevobj.h(file:///d:/reactos/win32ss/gdi/eng/pdevobj.h#L79-L149) PDEVOBJ 结构定义
pdevobj.c(file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L61-L87) PDEVOBJ_AllocPDEV
pdevobj.c(file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L102-L171) PDEVOBJ_vRelease(资源释放顺序)
pdevobj.c(file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L172-L241) PDEVOBJ_bEnablePDEV(DrvEnablePDEV 调用)
pdevobj.c(file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L253-L300) PDEVOBJ_vFilterDriverHooks(加速等级)
pdevobj.c(file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L462-L626) PDEVOBJ_Create(创建流程)
pdevobj.c(file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L643-L699) PDEVOBJ_bDynamicModeChange(状态交换)
pdevobj.c(file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L702-L760) PDEVOBJ_bSwitchMode(模式切换)

关联模块:

  • ldevobj.h(file:///d:/reactos/win32ss/gdi/eng/ldevobj.h) / ldevobj.c --- 逻辑设备对象(PDEV 的 pldev 引用)
  • mdevobj.h(file:///d:/reactos/win32ss/gdi/eng/mdevobj.h) / mdevobj.c --- 映射设备对象(多显示器,聚合多个 PDEV)
  • device.c(file:///d:/reactos/win32ss/gdi/eng/device.c) --- GRAPHICS_DEVICE 注册(PDEV 的 pGraphicsDevice)

关联文档:

  • 《ReactOS 图形系统分析_4.md》--- GDI 引擎整体架构(本文件是设备对象管理子模块)
  • 《ReactOS 图形系统分析_2.md》--- videoprt 层(PDEV 与驱动的关系)
  • ReactOS图形系统架构分析.md》--- 四层设备对象体系

本文档基于 ReactOS 源代码 win32ss/gdi/eng/pdevobj.cpdevobj.h 分析(2026 年 8 月)

相关推荐
ZJU_统一阿萨姆2 小时前
【推理优化】连续批处理:当推理吞吐量遇到天花板
人工智能·语言模型·系统架构
caimouse2 小时前
ReactOS 图形系统分析(4):GDI 引擎 (eng)
系统架构
caimouse3 小时前
ReactOS 图形系统分析(11):映射设备对象 — MDEVOBJ(多显示器)
系统架构·计算机外设
国科安芯1 天前
详解ADC 规则组外部触发:CH2、CH3 与 TRGO2
运维·网络·单片机·嵌入式硬件·mcu·系统架构
Dr.kangder1 天前
嵌入式面试总结(十)——流水线
单片机·嵌入式硬件·面试·职场和发展·系统架构·嵌入式
ZJU_统一阿萨姆1 天前
【推理优化】推理的本质:prefill 与 decode 两阶段
语言模型·系统架构
郑州光合科技余经理1 天前
餐饮预定系统架构拆解:订单链路、权限组织与私有化源码交付
java·开发语言·前端·数据库·人工智能·系统架构·php
youngerwang2 天前
【软件系统架构师案例分析每日深耕 Day 13】多质量属性权衡:电商大促架构设计
系统架构·案例分析·电商大促·多质量属性
火云牌神2 天前
前后端分离:约束 AI 分工,避免接口耦合与职责错乱
人工智能·系统架构·ai编程·前后端分离·vibecoding