ReactOS 图形系统分析(3):显示驱动 DDI framebuf.dll

ReactOS 图形系统分析(3):显示驱动 DDI framebuf.dll

1. 概述

framebuf.dll 是 ReactOS 的 通用帧缓冲显示驱动(Framebuffer Display Driver) ,源代码位于 win32ss/drivers/displays/framebuf/。它是显示栈中实现 DDI(Device Driver Interface) 的组件,直接向 win32k.sys 的 GDI 引擎注册绘图回调。

在 VirtualBox 虚拟机中,该驱动被实际加载(Loading: \SystemRoot\System32\framebuf.dll),与 vgapnp.sys(VBE miniport)、videoprt.sys(视频端口驱动)构成完整显示栈:

复制代码
win32k.sys (GDI 引擎)
    ↓ DDI 回调调用
framebuf.dll (显示驱动,本分析对象)
    ↓ EngDeviceIoControl (IOCTL)
videoprt.sys (视频端口驱动)
    ↓ HwStartIO (VRP)
vgapnp.sys (VBE miniport)
    ↓ INT 10 BIOS
VBE BIOS / 帧缓冲内存 (VirtualBox 虚拟显卡)

framebuf 如何通过 videoprt 把图像显示到屏幕:

整个显示过程分为建立映射阶段持续渲染阶段,framebuf 只在建立阶段通过 IOCTL 主动请求 videoprt 服务,渲染阶段则完全不经过 videoprt:

① 建立映射(一次性,由 DrvEnableSurface 完成):

复制代码
framebuf ──IOCTL_VIDEO_SET_CURRENT_MODE──▶ videoprt ──VRP──▶ vgapnp ──INT 10 0x4F02──▶ BIOS 切换显示模式
framebuf ──IOCTL_VIDEO_MAP_VIDEO_MEMORY─▶ videoprt ──VRP──▶ vgapnp ──VideoPortMapMemory──▶ 得到帧缓冲虚拟地址
                                                                                              │
framebuf ◀────────────────────── 帧缓冲虚拟地址 (ScreenPtr) ◀─────────────────────────────────┘

具体过程:framebuf 调用 EngDeviceIoControl 下发 IOCTL_VIDEO_SET_CURRENT_MODE,videoprt 的 VideoPortForwardDeviceControl 将其翻译为 VIDEO_REQUEST_PACKET 转发给 miniport 的 HwStartIO,vgapnp 通过 Int10CallBios(0x4F02) 让 VBE BIOS 把显卡切到目标模式;随后 framebuf 再下发 IOCTL_VIDEO_MAP_VIDEO_MEMORY,vgapnp 根据 VBE 模式信息中的 PhysBasePtr(显存物理地址)调用 VideoPortMapMemory 把它映射为内核虚拟地址并返回给 framebuf,存入 ppdev->ScreenPtr。最后 framebuf 用这个指针调用 EngCreateBitmap 创建"像素数据直接指向显存"的引擎位图,并 EngAssociateSurface 关联为显示表面。

② 持续渲染(每次画面更新,不经过 videoprt):

复制代码
应用程序绘图 → gdi32.dll → win32k (ntgdi) → GDI 引擎 (eng/) → DIB 引擎软件渲染
    → 直接写入 EngCreateBitmap 指向的显存虚拟地址 (ScreenPtr)
    → 显卡硬件把显存内容输出到屏幕

此时 framebuf 创建的表面和显存是同一块内存EngCreateBitmappvBits 直接传入 ScreenPtr,不复制像素)。GDI 引擎每次绘图都直接向这块内存写入颜色数据,写入完成后屏幕立刻反映最新内容------因为该内存就是显卡的帧缓冲(对 VirtualBox 而言就是 VRAM,VirtualBox 将其内容显示到宿主窗口)。此阶段 videoprt 和 vgapnp 完全不再参与,只有三种情况会再次穿过 videoprt:

场景 IOCTL 目的
调色板变化(8bpp) IOCTL_VIDEO_SET_COLOR_REGISTERS vgapnp 写 DAC 端口 / 调用 BIOS 0x4F09 更新硬件调色板
全屏切换 IOCTL_VIDEO_SET_CURRENT_MODE / IOCTL_VIDEO_RESET_DEVICE DrvAssertMode 重新设置或复位模式
关机/销毁 IOCTL_VIDEO_UNMAP_VIDEO_MEMORY DrvDisableSurface 解除显存映射

#mermaid-svg-2dh9XWCZhLnIzPs1{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-2dh9XWCZhLnIzPs1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2dh9XWCZhLnIzPs1 .error-icon{fill:#552222;}#mermaid-svg-2dh9XWCZhLnIzPs1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2dh9XWCZhLnIzPs1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2dh9XWCZhLnIzPs1 .marker.cross{stroke:#333333;}#mermaid-svg-2dh9XWCZhLnIzPs1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2dh9XWCZhLnIzPs1 p{margin:0;}#mermaid-svg-2dh9XWCZhLnIzPs1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2dh9XWCZhLnIzPs1 .cluster-label text{fill:#333;}#mermaid-svg-2dh9XWCZhLnIzPs1 .cluster-label span{color:#333;}#mermaid-svg-2dh9XWCZhLnIzPs1 .cluster-label span p{background-color:transparent;}#mermaid-svg-2dh9XWCZhLnIzPs1 .label text,#mermaid-svg-2dh9XWCZhLnIzPs1 span{fill:#333;color:#333;}#mermaid-svg-2dh9XWCZhLnIzPs1 .node rect,#mermaid-svg-2dh9XWCZhLnIzPs1 .node circle,#mermaid-svg-2dh9XWCZhLnIzPs1 .node ellipse,#mermaid-svg-2dh9XWCZhLnIzPs1 .node polygon,#mermaid-svg-2dh9XWCZhLnIzPs1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2dh9XWCZhLnIzPs1 .rough-node .label text,#mermaid-svg-2dh9XWCZhLnIzPs1 .node .label text,#mermaid-svg-2dh9XWCZhLnIzPs1 .image-shape .label,#mermaid-svg-2dh9XWCZhLnIzPs1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-2dh9XWCZhLnIzPs1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2dh9XWCZhLnIzPs1 .rough-node .label,#mermaid-svg-2dh9XWCZhLnIzPs1 .node .label,#mermaid-svg-2dh9XWCZhLnIzPs1 .image-shape .label,#mermaid-svg-2dh9XWCZhLnIzPs1 .icon-shape .label{text-align:center;}#mermaid-svg-2dh9XWCZhLnIzPs1 .node.clickable{cursor:pointer;}#mermaid-svg-2dh9XWCZhLnIzPs1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2dh9XWCZhLnIzPs1 .arrowheadPath{fill:#333333;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2dh9XWCZhLnIzPs1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2dh9XWCZhLnIzPs1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2dh9XWCZhLnIzPs1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2dh9XWCZhLnIzPs1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2dh9XWCZhLnIzPs1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2dh9XWCZhLnIzPs1 .cluster text{fill:#333;}#mermaid-svg-2dh9XWCZhLnIzPs1 .cluster span{color:#333;}#mermaid-svg-2dh9XWCZhLnIzPs1 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-2dh9XWCZhLnIzPs1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2dh9XWCZhLnIzPs1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-2dh9XWCZhLnIzPs1 .icon-shape,#mermaid-svg-2dh9XWCZhLnIzPs1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2dh9XWCZhLnIzPs1 .icon-shape p,#mermaid-svg-2dh9XWCZhLnIzPs1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2dh9XWCZhLnIzPs1 .icon-shape .label rect,#mermaid-svg-2dh9XWCZhLnIzPs1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2dh9XWCZhLnIzPs1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2dh9XWCZhLnIzPs1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2dh9XWCZhLnIzPs1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 渲染阶段(持续,绕过 videoprt)
建立阶段(一次)
IOCTL_SET_CURRENT_MODE

IOCTL_MAP_VIDEO_MEMORY
HwStartIO
0x4F02/VideoPortMapMemory
帧缓冲虚拟地址
EngCreateBitmap

pvBits=ScreenPtr
直接写像素
显存内容
framebuf

DrvEnableSurface
videoprt

IRP→VRP 转发
vgapnp
显存/BIOS
GDI 显示表面

(与显存同一块内存)
应用程序
GDI 引擎 DIB 软件渲染
显卡输出到屏幕

总结: framebuf 通过 videoprt(及 miniport)完成"模式设置 + 显存映射"后,就把 videoprt 的桥梁作用"用完即弃"------之后的画面显示是 GDI 引擎向显存直写 + 显卡硬件自动刷新的纯内存操作,videoprt 只在模式/调色板/复位等控制性操作时才重新介入。

1.2 颜色数据(像素)在帧缓冲中的结构

framebuf 写入帧缓冲的"颜色数据"不是简单的 RGB 三元组,而是按显示模式位深打包的原始像素值。其结构由 GDI 表面(SURFOBJ)与像素格式共同决定。

① 表面内存布局 --- SURFOBJ 三要素

EngCreateBitmap 创建的表面在内核中对应 SURFOBJ 结构,GDI 引擎通过它定位每个像素:

c 复制代码
typedef struct _SURFOBJ {
  DHSURF  dhsurf;
  HSURF   hsurf;
  DHPDEV  dhpdev;          // → 关联的 PDEV(framebuf 的 PPDEV)
  HDEV    hdev;
  SIZEL   sizlBitmap;      // 表面尺寸(宽×高,即 ScreenWidth×ScreenHeight)
  ULONG   cjBits;          // 像素数据总字节数
  PVOID   pvBits;          // 像素数据起始地址(= 帧缓冲 ScreenPtr)
  PVOID   pvScan0;         // 第一行起始地址(TOP-DOWN 时 = pvBits)
  LONG    lDelta;          // 行距:一行像素的字节数(= ScreenDelta/pitch)
  ULONG   iUniq;
  ULONG   iBitmapFormat;   // 像素格式(BMF_8BPP/16BPP/24BPP/32BPP)
  USHORT  iType;           // STYPE_BITMAP
  ...
} SURFOBJ;

像素寻址公式(任意坐标 (x, y)):

复制代码
像素地址 = pvScan0 + y × lDelta + x × (BitsPerPixel / 8)

其中 lDelta(= ScreenDelta)来自 VBE 模式信息的 BytesPerScanLine/LinBytesPerScanLine可能大于 宽 × 每像素字节数(存在行尾填充对齐),因此相邻两行的首像素地址差固定为 lDelta

② 四种像素格式的位结构

帧缓冲内存是一维字节流,按每像素占用字节数解析:
#mermaid-svg-wOdrhwsaYUezJW35{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-wOdrhwsaYUezJW35 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wOdrhwsaYUezJW35 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wOdrhwsaYUezJW35 .error-icon{fill:#552222;}#mermaid-svg-wOdrhwsaYUezJW35 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wOdrhwsaYUezJW35 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wOdrhwsaYUezJW35 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wOdrhwsaYUezJW35 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wOdrhwsaYUezJW35 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wOdrhwsaYUezJW35 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wOdrhwsaYUezJW35 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wOdrhwsaYUezJW35 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wOdrhwsaYUezJW35 .marker.cross{stroke:#333333;}#mermaid-svg-wOdrhwsaYUezJW35 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wOdrhwsaYUezJW35 p{margin:0;}#mermaid-svg-wOdrhwsaYUezJW35 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wOdrhwsaYUezJW35 .cluster-label text{fill:#333;}#mermaid-svg-wOdrhwsaYUezJW35 .cluster-label span{color:#333;}#mermaid-svg-wOdrhwsaYUezJW35 .cluster-label span p{background-color:transparent;}#mermaid-svg-wOdrhwsaYUezJW35 .label text,#mermaid-svg-wOdrhwsaYUezJW35 span{fill:#333;color:#333;}#mermaid-svg-wOdrhwsaYUezJW35 .node rect,#mermaid-svg-wOdrhwsaYUezJW35 .node circle,#mermaid-svg-wOdrhwsaYUezJW35 .node ellipse,#mermaid-svg-wOdrhwsaYUezJW35 .node polygon,#mermaid-svg-wOdrhwsaYUezJW35 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wOdrhwsaYUezJW35 .rough-node .label text,#mermaid-svg-wOdrhwsaYUezJW35 .node .label text,#mermaid-svg-wOdrhwsaYUezJW35 .image-shape .label,#mermaid-svg-wOdrhwsaYUezJW35 .icon-shape .label{text-anchor:middle;}#mermaid-svg-wOdrhwsaYUezJW35 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wOdrhwsaYUezJW35 .rough-node .label,#mermaid-svg-wOdrhwsaYUezJW35 .node .label,#mermaid-svg-wOdrhwsaYUezJW35 .image-shape .label,#mermaid-svg-wOdrhwsaYUezJW35 .icon-shape .label{text-align:center;}#mermaid-svg-wOdrhwsaYUezJW35 .node.clickable{cursor:pointer;}#mermaid-svg-wOdrhwsaYUezJW35 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wOdrhwsaYUezJW35 .arrowheadPath{fill:#333333;}#mermaid-svg-wOdrhwsaYUezJW35 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wOdrhwsaYUezJW35 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wOdrhwsaYUezJW35 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wOdrhwsaYUezJW35 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wOdrhwsaYUezJW35 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wOdrhwsaYUezJW35 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wOdrhwsaYUezJW35 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wOdrhwsaYUezJW35 .cluster text{fill:#333;}#mermaid-svg-wOdrhwsaYUezJW35 .cluster span{color:#333;}#mermaid-svg-wOdrhwsaYUezJW35 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-wOdrhwsaYUezJW35 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wOdrhwsaYUezJW35 rect.text{fill:none;stroke-width:0;}#mermaid-svg-wOdrhwsaYUezJW35 .icon-shape,#mermaid-svg-wOdrhwsaYUezJW35 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wOdrhwsaYUezJW35 .icon-shape p,#mermaid-svg-wOdrhwsaYUezJW35 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wOdrhwsaYUezJW35 .icon-shape .label rect,#mermaid-svg-wOdrhwsaYUezJW35 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wOdrhwsaYUezJW35 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wOdrhwsaYUezJW35 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wOdrhwsaYUezJW35 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 帧缓冲内存字节流 (低地址 → 高地址)
像素(0,0)
像素(1,0)
像素(2,0)
...

BMF_8BPP(1 字节/像素)--- 调色板索引:

复制代码
bit:  7     6     5     4     3     2     1     0
     ┌─────────────────────────────────────────────┐
     │         8 位调色板索引 (0~255)               │
     └─────────────────────────────────────────────┘

写入的值是索引 而非颜色本身,颜色由硬件调色板(CLUT,256 项 × 32 位 RGB)映射。framebuf 通过 IOCTL_VIDEO_SET_COLOR_REGISTERS 维护这份 CLUT。

BMF_16BPP(2 字节/像素,USHORT)--- 高彩色:

布局由 RedMask/GreenMask/BlueMask 决定,常见两种:

复制代码
RGB565 (RedMask=0xF800):                        RGB555 (RedMask=0x7C00):
bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0      bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
     │ R R R R R G G G G G G B B B B B │              │   R R R R R G G G G G B B B B B   │

内存中(小端):低字节在前。R/G/B 各分量从 8 位精度的 COLORREF 右移截断得到。

BMF_24BPP(3 字节/像素)--- 真彩色:

复制代码
byte:  0          1          2
     ┌──────────┬──────────┬──────────┐
     │   Blue   │  Green   │   Red    │
     └──────────┴──────────┴──────────┘

内存顺序为 B-G-R (与 32 位值 0x00RRGGBB 小端存储一致)。每像素 3 字节,无填充。

BMF_32BPP(4 字节/像素,ULONG)--- 真彩色 + 保留字节:

复制代码
dword 值 (小端):  0x00RRGGBB
内存字节顺序:      byte0=Blue  byte1=Green  byte2=Red  byte3=0x00(保留/Alpha)

     ┌──────────┬──────────┬──────────┬──────────┐
     │   Blue   │  Green   │   Red    │  0x00    │
     └──────────┴──────────┴──────────┴──────────┘
③ 颜色掩码(Color Mask)的作用

对于 16/32bpp,R/G/B 分量在像素值中的位置不固定 ,由 VBE 模式信息返回的掩码决定(framebuf 存入 ppdev->RedMask/GreenMask/BlueMask,VirtualBox 32bpp 典型值为 0xFF0000 / 0xFF00 / 0xFF):

复制代码
像素值 = (R << RedFieldPosition) | (G << GreenFieldPosition) | (B << BlueFieldPosition)

例如 RGB565:R 左移 11 位、G 左移 5 位、B 左移 0 位。掩码还用于:

  • 创建 DirectDraw 像素格式(ppdev->ddpfDisplay
  • 8bpp 以上的默认调色板(EngCreatePalette(PAL_BITFIELDS, ..., RedMask, GreenMask, BlueMask)
  • framebuf 本身不转换颜色,转换由 GDI 引擎的 XLATEOBJ 完成
④ 颜色转换流程(COLORREF → 像素值)

GDI 引擎绘图时传入的 COLORREF 是 0x00BBGGRR 格式,写入帧缓冲前经过转换:

复制代码
应用程序: COLORREF = 0x00BBGGRR (红=0xFF0000)
    ↓ GDI 引擎 / XLATEOBJ 颜色翻译
像素值 = 0x00RRGGBB (按目标格式掩码重排,如 32bpp)
    ↓ DIB 引擎按小端写入
帧缓冲字节: [BB] [GG] [RR] [00]
    ↓ 显卡硬件按模式解析
屏幕显示该像素颜色

关键点: framebuf 表面是 DIB 格式位图,GDI 引擎直接按 iBitmapFormat 对应的 DIB 函数表(DibFunctionsForBitmapFormat[],见 win32ss/gdi/dib/dib.c)完成"COLORREF → 像素值 → 写显存"全流程;framebuf 只提供 ScreenPtr 这个目标内存地址。

1.1 模块文件构成

文件 功能
enable.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/enable.c) DrvEnableDriver(DDI 函数表)、DrvEnablePDEV/CompletePDEV/DisablePDEV、DirectDraw 使能
screen.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/screen.c) 模式枚举(GetAvailableModes)、模式选择、GDIINFO/DEVINFO 填充、DrvGetModes
surface.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/surface.c) DrvEnableSurface(设置模式+映射帧缓冲+创建表面)、DrvDisableSurface、DrvAssertMode
palette.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/palette.c) 默认调色板初始化、IntSetPalette(CLUT 下发)、DrvSetPalette
pointer.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/pointer.c) 鼠标指针(软件光标经 GDI,或实验性硬件光标)
dd.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/dd.c) DirectDraw 2D 回调(DdCanCreateSurface、DdCreateSurface)
ddenable.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/ddenable.c) DirectDraw 初始化(DrvEnableDirectDraw、DrvGetDirectDrawInfo)
framebuf.h(file:///d:/reactos/win32ss/drivers/displays/framebuf/framebuf.h) PDEV 结构定义、函数声明

1.2 构建配置

cmake 复制代码
add_library(framebuf MODULE ${SOURCE} framebuf.rc)
set_module_type(framebuf kerneldll ENTRYPOINT DrvEnableDriver 12)  # 内核 DLL,入口 DrvEnableDriver
add_importlibs(framebuf win32k)     # 导入 win32k(Eng* 引擎函数)
add_cd_file(TARGET framebuf DESTINATION reactos/system32)  # 安装到 system32

关键点: 类型为 kerneldll(非驱动),安装到 system32(而非 drivers),入口点是 DrvEnableDriver,导入 win32k 以调用 Eng* 引擎服务函数。


2. DDI 函数表与驱动入口

2.1 DrvEnableDriver --- 驱动入口

win32k 加载 framebuf.dll 后调用其导出入口 DrvEnableDriver,获取 DDI 函数表:

c 复制代码
static DRVFN DrvFunctionTable[] =
{
   {INDEX_DrvEnablePDEV, (PFN)DrvEnablePDEV},
   {INDEX_DrvCompletePDEV, (PFN)DrvCompletePDEV},
   {INDEX_DrvDisablePDEV, (PFN)DrvDisablePDEV},
   {INDEX_DrvEnableSurface, (PFN)DrvEnableSurface},
   {INDEX_DrvDisableSurface, (PFN)DrvDisableSurface},
   {INDEX_DrvAssertMode, (PFN)DrvAssertMode},
   {INDEX_DrvGetModes, (PFN)DrvGetModes},
   {INDEX_DrvSetPalette, (PFN)DrvSetPalette},
   {INDEX_DrvSetPointerShape, (PFN)DrvSetPointerShape},
   {INDEX_DrvMovePointer, (PFN)DrvMovePointer},
   {INDEX_DrvEnableDirectDraw, (PFN)DrvEnableDirectDraw},
   {INDEX_DrvDisableDirectDraw, (PFN)DrvDisableDirectDraw},
};

BOOL APIENTRY DrvEnableDriver(ULONG iEngineVersion, ULONG cj, PDRVENABLEDATA pded)
{
   pded->c = sizeof(DrvFunctionTable) / sizeof(DRVFN);   // 12 个 DDI 函数
   pded->pdrvfn = DrvFunctionTable;
   pded->iDriverVersion = DDI_DRIVER_VERSION_NT5;       // NT 5.x DDI 版本
   return TRUE;
}

特点: 函数表很小(12 项)------framebuf 没有实现 DrvBitBltDrvTextOutDrvStrokePath 等绘图函数。所有绘图操作完全由 GDI 引擎的软件渲染(DIB 引擎)完成,framebuf 只负责提供"画布"(帧缓冲表面)和模式管理。这使它成为一个极简但通用的显示驱动。


3. 核心数据结构 --- PDEV

c 复制代码
typedef struct _PDEV
{
   HANDLE hDriver;            // 设备句柄(EngDeviceIoControl 用)
   HDEV hDevEng;              // 引擎设备句柄(DrvCompletePDEV 保存)
   HSURF hSurfEng;            // 引擎表面句柄(DrvEnableSurface 创建)

   ULONG ModeIndex;           // 当前模式索引(vgapnp 的 ModeIndex)
   ULONG ScreenWidth;         // 屏幕宽(像素)
   ULONG ScreenHeight;        // 屏幕高(像素)
   ULONG ScreenDelta;         // 每行字节数(stride/pitch)
   BYTE BitsPerPixel;         // 每像素位数 (8/16/24/32)

   ULONG RedMask, GreenMask, BlueMask;  // 颜色掩码
   BYTE PaletteShift;         // 8bpp 调色板移位

   PVOID ScreenPtr;           // 帧缓冲指针(映射后的虚拟地址)
   HPALETTE DefaultPalette;   // 默认调色板
   PALETTEENTRY *PaletteEntries;  // 8bpp 调色板条目

#ifdef EXPERIMENTAL_MOUSE_CURSOR_SUPPORT
   /* 实验性硬件光标支持 */
   VIDEO_POINTER_ATTRIBUTES PointerAttributes;
   XLATEOBJ *PointerXlateObject;
   HSURF PointerColorSurface;
   HSURF PointerMaskSurface;
   HSURF PointerSaveSurface;
   POINTL PointerHotSpot;
#endif

   /* DirectX 支持 */
   DWORD iDitherFormat;       // 抖动格式(BMF_8BPP ~ BMF_32BPP)
   ULONG MemHeight;           // 显存高度(可能大于屏幕高度)
   ULONG MemWidth;            // 显存宽度
   DWORD dwHeap;              // DirectDraw 堆数量
   VIDEOMEMORY* pvmList;      // DirectDraw 视频内存描述
   BOOL bDDInitialized;       // DirectDraw 初始化标志
   DDPIXELFORMAT ddpfDisplay; // DirectDraw 像素格式
} PDEV, *PPDEV;

PDEV 生命周期:

复制代码
DrvEnablePDEV      → 分配 PDEV + IntInitScreenInfo + IntInitDefaultPalette
DrvCompletePDEV    → 保存 hDevEng
DrvEnableSurface   → 设置模式 + 映射帧缓冲 + EngCreateBitmap + EngAssociateSurface
   ... 桌面运行 ...
DrvDisableSurface  → 删除表面 + 解除帧缓冲映射
DrvDisablePDEV     → 删除调色板 + 释放 PDEV

4. 屏幕信息初始化 --- screen.c

4.1 模式枚举 --- GetAvailableModes

通过 EngDeviceIoControl 向 miniport 查询模式:

c 复制代码
DWORD GetAvailableModes(HANDLE hDriver, PVIDEO_MODE_INFORMATION *ModeInfo, DWORD *ModeInfoSize)
{
   /* 1. 查询模式数量 */
   EngDeviceIoControl(hDriver, IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES, NULL, 0,
                      &Modes, sizeof(VIDEO_NUM_MODES), &ulTemp);

   /* 2. 分配缓冲区并查询全部模式 */
   *ModeInfo = EngAllocMem(0, Modes.NumModes * Modes.ModeInformationLength, ALLOC_TAG);
   EngDeviceIoControl(hDriver, IOCTL_VIDEO_QUERY_AVAIL_MODES, NULL, 0,
                      *ModeInfo, Modes.NumModes * Modes.ModeInformationLength, &ulTemp);

   /* 3. 过滤不支持的显示驱动模式(内部机制:Length 置 0) */
   while (ulTemp--)
   {
      if ((ModeInfoPtr->NumberOfPlanes != 1) ||          // 必须单平面
          !(ModeInfoPtr->AttributeFlags & VIDEO_MODE_GRAPHICS) ||  // 必须图形模式
          ((BitsPerPlane != 8) && (BitsPerPlane != 16) &&
           (BitsPerPlane != 24) && (BitsPerPlane != 32)))          // 必须 8/16/24/32bpp
      {
         ModeInfoPtr->Length = 0;   // 标记不支持
      }
   }
}

关键过滤规则: framebuf 只支持 1 平面、图形模式、8/16/24/32 位色深。vgapnp 返回的模式(含 15bpp 等)在此被过滤。

4.2 模式选择 --- IntInitScreenInfo

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





IntInitScreenInfo
GetAvailableModes 获取模式列表
pDevMode 全为 0?

(无指定模式)
选择第一个支持的模式
匹配 dmPelsWidth/dmPelsHeight/

dmBitsPerPel/dmDisplayFrequency
找到匹配模式?
返回 FALSE
保存到 PDEV

ModeIndex/ScreenWidth/Height/Delta

BitsPerPixel/RedMask 等
填充 GDIINFO

版本/技术/分辨率/色深/刷新率
填充 DEVINFO

默认字体 System/MS Sans Serif/Courier

flGraphicsCaps
BitsPerPixel == 8?
GCAPS_PALMANAGED

iDitherFormat = BMF_8BPP

PaletteShift = 8 - DAC 位数
16/24/32 bpp
iDitherFormat = BMF_16BPP/24BPP/32BPP

ulNumColors = -1 (真彩色)
返回 TRUE

GDIINFO 关键字段:

  • ulTechnology = DT_RASDISPLAY --- 光栅显示设备
  • cBitsPixel / cPlanes --- 色深与平面数
  • ulDACRed/Green/Blue --- DAC 位数(来自 miniport 模式信息)
  • ciDevice --- 颜色特性(优先从 IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES 获取,失败用默认 sRGB 色度值)
  • ulHTOutputFormat --- 半色调输出格式(HT_FORMAT_8BPP/16BPP/24BPP/32BPP)

DEVINFO 关键字段:

  • lfDefaultFont = "System"(16x7,粗体)--- 系统默认字体
  • lfAnsiVarFont = "MS Sans Serif"(12x9)--- 可变宽字体
  • lfAnsiFixFont = "Courier"(12x9)--- 固定宽字体
  • iDitherFormat --- framebuf 支持的位图格式
  • flGraphicsCaps = GCAPS_PALMANAGED(仅 8bpp)

4.3 DrvGetModes --- 模式列表输出

DrvGetModes 被 win32k 调用以枚举可用显示模式(配合显示控制面板/设置程序):

  • pdm == NULL 时返回所需缓冲大小(ModeCount * sizeof(DEVMODEW)
  • 否则逐个模式填充 DEVMODEW(设备名 "framebuf"、位深、分辨率、刷新率)

5. 表面管理 --- surface.c

5.1 DrvEnableSurface --- 创建显示表面

这是 framebuf 最核心的函数,完成"硬件帧缓冲 → GDI 表面"的绑定:
#mermaid-svg-EquCmJHyXehO6Tq2{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-EquCmJHyXehO6Tq2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EquCmJHyXehO6Tq2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EquCmJHyXehO6Tq2 .error-icon{fill:#552222;}#mermaid-svg-EquCmJHyXehO6Tq2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EquCmJHyXehO6Tq2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EquCmJHyXehO6Tq2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EquCmJHyXehO6Tq2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EquCmJHyXehO6Tq2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EquCmJHyXehO6Tq2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EquCmJHyXehO6Tq2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EquCmJHyXehO6Tq2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EquCmJHyXehO6Tq2 .marker.cross{stroke:#333333;}#mermaid-svg-EquCmJHyXehO6Tq2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EquCmJHyXehO6Tq2 p{margin:0;}#mermaid-svg-EquCmJHyXehO6Tq2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EquCmJHyXehO6Tq2 .cluster-label text{fill:#333;}#mermaid-svg-EquCmJHyXehO6Tq2 .cluster-label span{color:#333;}#mermaid-svg-EquCmJHyXehO6Tq2 .cluster-label span p{background-color:transparent;}#mermaid-svg-EquCmJHyXehO6Tq2 .label text,#mermaid-svg-EquCmJHyXehO6Tq2 span{fill:#333;color:#333;}#mermaid-svg-EquCmJHyXehO6Tq2 .node rect,#mermaid-svg-EquCmJHyXehO6Tq2 .node circle,#mermaid-svg-EquCmJHyXehO6Tq2 .node ellipse,#mermaid-svg-EquCmJHyXehO6Tq2 .node polygon,#mermaid-svg-EquCmJHyXehO6Tq2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EquCmJHyXehO6Tq2 .rough-node .label text,#mermaid-svg-EquCmJHyXehO6Tq2 .node .label text,#mermaid-svg-EquCmJHyXehO6Tq2 .image-shape .label,#mermaid-svg-EquCmJHyXehO6Tq2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-EquCmJHyXehO6Tq2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EquCmJHyXehO6Tq2 .rough-node .label,#mermaid-svg-EquCmJHyXehO6Tq2 .node .label,#mermaid-svg-EquCmJHyXehO6Tq2 .image-shape .label,#mermaid-svg-EquCmJHyXehO6Tq2 .icon-shape .label{text-align:center;}#mermaid-svg-EquCmJHyXehO6Tq2 .node.clickable{cursor:pointer;}#mermaid-svg-EquCmJHyXehO6Tq2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EquCmJHyXehO6Tq2 .arrowheadPath{fill:#333333;}#mermaid-svg-EquCmJHyXehO6Tq2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EquCmJHyXehO6Tq2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EquCmJHyXehO6Tq2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EquCmJHyXehO6Tq2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EquCmJHyXehO6Tq2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EquCmJHyXehO6Tq2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EquCmJHyXehO6Tq2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EquCmJHyXehO6Tq2 .cluster text{fill:#333;}#mermaid-svg-EquCmJHyXehO6Tq2 .cluster span{color:#333;}#mermaid-svg-EquCmJHyXehO6Tq2 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-EquCmJHyXehO6Tq2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EquCmJHyXehO6Tq2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-EquCmJHyXehO6Tq2 .icon-shape,#mermaid-svg-EquCmJHyXehO6Tq2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EquCmJHyXehO6Tq2 .icon-shape p,#mermaid-svg-EquCmJHyXehO6Tq2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EquCmJHyXehO6Tq2 .icon-shape .label rect,#mermaid-svg-EquCmJHyXehO6Tq2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EquCmJHyXehO6Tq2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EquCmJHyXehO6Tq2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EquCmJHyXehO6Tq2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 失败
成功
失败
成功
8
16
24
32
其他
NULL
失败
成功
DrvEnableSurface
EngDeviceIoControl

IOCTL_VIDEO_SET_CURRENT_MODE

设置 ModeIndex
返回 NULL
EngDeviceIoControl

IOCTL_VIDEO_MAP_VIDEO_MEMORY

映射帧缓冲
ppdev->ScreenPtr = FrameBufferBase

(帧缓冲虚拟地址)
BitsPerPixel?
IntSetPalette 下发 256 色

BitmapType = BMF_8BPP
BMF_16BPP
BMF_24BPP
BMF_32BPP
EngCreateBitmap

创建引擎位图

(ScreenSize, ScreenDelta, BitmapType,

BMF_TOPDOWN, ScreenPtr)
EngAssociateSurface

将表面关联到 hDevEng 设备
EngDeleteSurface
ppdev->hSurfEng = hSurface
返回 hSurface

c 复制代码
HSURF APIENTRY DrvEnableSurface(DHPDEV dhpdev)
{
   /* 1. 设置显示模式(调 vgapnp 的 0x4F02) */
   EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_CURRENT_MODE,
                      &ppdev->ModeIndex, sizeof(ULONG), NULL, 0, &ulTemp);

   /* 2. 映射帧缓冲(调 vgapnp 的 VideoPortMapMemory) */
   VideoMemory.RequestedVirtualAddress = NULL;
   EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_MAP_VIDEO_MEMORY,
                      &VideoMemory, sizeof(VIDEO_MEMORY),
                      &VideoMemoryInfo, sizeof(VIDEO_MEMORY_INFORMATION), &ulTemp);
   ppdev->ScreenPtr = VideoMemoryInfo.FrameBufferBase;

   /* 3. 围绕帧缓冲创建引擎位图(关键:不复制像素,直接指向帧缓冲) */
   hSurface = (HSURF)EngCreateBitmap(ScreenSize, ppdev->ScreenDelta, BitmapType,
                                     BMF_TOPDOWN,        // 自顶向下布局
                                     ppdev->ScreenPtr);  // 像素数据 = 帧缓冲

   /* 4. 关联表面到设备 */
   EngAssociateSurface(hSurface, ppdev->hDevEng, 0);
}

设计精髓: EngCreateBitmappvBits 参数直接传入帧缓冲指针。GDI 引擎后续的所有软件渲染(DIB 引擎 BitBlt/TextOut/线条)都直接写帧缓冲内存,无需任何硬件加速,天然适配所有 VBE 兼容显卡。

5.2 DrvDisableSurface --- 销毁表面

c 复制代码
VOID APIENTRY DrvDisableSurface(DHPDEV dhpdev)
{
   EngDeleteSurface(ppdev->hSurfEng);       // 删除引擎表面
   ppdev->hSurfEng = NULL;
   /* 解除帧缓冲映射 */
   VideoMemory.RequestedVirtualAddress = ppdev->ScreenPtr;
   EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_UNMAP_VIDEO_MEMORY,
                      &VideoMemory, sizeof(VIDEO_MEMORY), NULL, 0, &ulTemp);
}

5.3 DrvAssertMode --- 模式断言(全屏切换用)

c 复制代码
BOOL APIENTRY DrvAssertMode(DHPDEV dhpdev, BOOL bEnable)
{
   if (bEnable)
   {
      /* 重新设置模式 + 8bpp 时重设调色板 */
      EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_CURRENT_MODE, ...);
   }
   else
   {
      /* 调用 miniport 复位设备到已知状态 */
      EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_RESET_DEVICE, ...);
   }
}

6. 调色板管理 --- palette.c

6.1 默认调色板初始化 --- IntInitDefaultPalette

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

IntInitDefaultPalette
BitsPerPixel > 8?
EngCreatePalette(PAL_BITFIELDS)

用 RedMask/GreenMask/BlueMask

创建真彩色调色板
分配 256 个 PALETTEENTRY
生成 8-3-3 全彩渐变调色板

R=(i>>5)&7, G=(i>>3)&3, B=i&7
嵌入 20 色系统 BASEPALETTE

前 10 项在索引 0-9

后 10 项在索引 246-255
EngCreatePalette(PAL_INDEXED, 256)

创建索引调色板
保存到 ppdev->DefaultPalette

并写入 pDevInfo->hpalDefault
返回结果

BASEPALETTE(20 色系统基础色): 包含窗口边框、按钮等 GUI 元素必需的标准颜色(黑、暗红/绿/蓝、亮红/绿/蓝、灰阶等)。

6.2 调色板下发 --- IntSetPalette

c 复制代码
BOOL APIENTRY IntSetPalette(DHPDEV dhpdev, PPALETTEENTRY ppalent, ULONG iStart, ULONG cColors)
{
   /* 构造 VIDEO_CLUT 结构 */
   ClutSize = sizeof(VIDEO_CLUT) + (cColors * sizeof(ULONG));
   pClut->FirstEntry = iStart;
   pClut->NumEntries = cColors;
   memcpy(&pClut->LookupTable[0].RgbLong, ppalent, sizeof(ULONG) * cColors);

   /* 8bpp 调色板移位(适配 DAC 位数) */
   if (ppdev->PaletteShift)
   {
      pClut->LookupTable[i].RgbArray.Red >>= PaletteShift;  // 同理 Green/Blue
   }

   /* 通过 IOCTL 下发到 miniport(vgapnp → DAC 端口或 BIOS 0x4F09) */
   EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_COLOR_REGISTERS,
                      pClut, ClutSize, NULL, 0, &cColors);
}

6.3 DrvSetPalette --- GDI 调色板实现回调

win32k 在调色板需要实现时调用,先通过 PALOBJ_cGetColors 从 PALOBJ 取出颜色,再调用 IntSetPalette 下发。


7. 鼠标指针 --- pointer.c

7.1 默认实现(软件光标)

EXPERIMENTAL_MOUSE_CURSOR_SUPPORT 默认未定义,因此使用最简单的软件光标方案------完全委托给 GDI 引擎:

c 复制代码
ULONG APIENTRY DrvSetPointerShape(...)
{
   /* 拒绝自行绘制,让 GDI 引擎在表面上层绘制指针 */
   return EngSetPointerShape(pso, psoMask, psoColor, pxlo, xHot, yHot, x, y, prcl, fl);
}

VOID APIENTRY DrvMovePointer(...)
{
   EngMovePointer(pso, x, y, prcl);
}

GDI 引擎会在桌面绘制后把光标画在表面最上层(软件光标,无需硬件支持)。

7.2 实验性硬件光标实现

若定义 EXPERIMENTAL_MOUSE_CURSOR_SUPPORT,则实现完整的硬件光标逻辑:

  • IntShowMousePointer:先把光标下的像素保存到 PointerSaveSurface,再把光标(颜色表面 + 掩码表面)通过 EngBitBlt 叠加到屏幕
  • IntHideMousePointer:用保存的像素恢复被光标覆盖的区域
  • DrvSetPointerShape:创建颜色表面(光标彩色图)、掩码表面(AND/XOR 掩码)、保存表面
  • DrvMovePointer:先隐藏再移动到新位置再显示

该实现通过 EngBitBlt(ROP 0xAACC 等)实现光标合成,属于 GDI 级软件光标增强。


8. DirectDraw 支持 --- dd.c / ddenable.c

framebuf 提供基础 DirectDraw HAL 支持(让 DirectX 应用能创建显存表面)。

8.1 DrvEnableDirectDraw --- DirectDraw 使能

c 复制代码
BOOL APIENTRY DrvEnableDirectDraw(DHPDEV dhpdev, DD_CALLBACKS *pCallBacks, ...)
{
   /* 设置像素格式 */
   ppdev->ddpfDisplay.dwRGBBitCount = ppdev->BitsPerPixel;
   ppdev->ddpfDisplay.dwRBitMask = ppdev->RedMask;   // 颜色掩码
   ppdev->ddpfDisplay.dwGBitMask = ppdev->GreenMask;
   ppdev->ddpfDisplay.dwBBitMask = ppdev->BlueMask;
   ppdev->ddpfDisplay.dwFlags = DDPF_RGB;
   /* 8bpp → DDPF_PALETTEINDEXED8; 32bpp → Alpha 掩码 0xFF000000 */

   /* 注册 HAL 回调 */
   pCallBacks->CanCreateSurface = (PDD_CANCREATESURFACE)DdCanCreateSurface;
   pCallBacks->CreateSurface = (PDD_CREATESURFACE)DdCreateSurface;
}

8.2 DdCanCreateSurface / DdCreateSurface

  • DdCanCreateSurface:拒绝 Z-Buffer/显存表面、不同像素格式的创建(仅支持与显示格式相同的表面)
  • DdCreateSurface:为 DirectDraw 表面分配内存(系统内存/显存)

8.3 DrvGetDirectDrawInfo --- 显存堆描述

c 复制代码
BOOL APIENTRY DrvGetDirectDrawInfo(DHPDEV dhpdev, DD_HALINFO *pHalInfo, ...)
{
   /* 计算显存总量 = (MemHeight - ScreenHeight) * ScreenDelta */
   pHalInfo->ddCaps.dwVidMemTotal = (ppdev->MemHeight - ppdev->ScreenHeight) * ppdev->ScreenDelta;

   /* 主表面信息 */
   pHalInfo->vmiData.pvPrimary = ppdev->ScreenPtr;   // 帧缓冲指针
   pHalInfo->vmiData.lDisplayPitch = ppdev->ScreenDelta;

   /* 显存堆:屏幕下方剩余区域为 offscreen heap */
   pvmList->fpStart = ppdev->ScreenHeight * ppdev->ScreenDelta;
   pvmList->fpEnd = ppdev->MemHeight * ppdev->ScreenDelta - 1;
}

9. 与上下层的完整交互

9.1 IOCTL 依赖清单(framebuf → videoprt/miniport)

IOCTL 用途 下层处理
IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES 查询模式数量 vgapnp VBEQueryNumAvailModes
IOCTL_VIDEO_QUERY_AVAIL_MODES 查询模式列表 vgapnp VBEQueryAvailModes
IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES 颜色特性 miniport
IOCTL_VIDEO_SET_CURRENT_MODE 设置显示模式 vgapnp VBESetCurrentMode (0x4F02)
IOCTL_VIDEO_MAP_VIDEO_MEMORY 映射帧缓冲 vgapnp VBEMapVideoMemory
IOCTL_VIDEO_UNMAP_VIDEO_MEMORY 解除映射 vgapnp VBEUnmapVideoMemory
IOCTL_VIDEO_RESET_DEVICE 复位设备 vgapnp VBEResetDevice
IOCTL_VIDEO_SET_COLOR_REGISTERS 设置调色板 vgapnp VBESetColorRegisters

9.2 启动加载时序

vgapnp.sys videoprt.sys framebuf.dll win32k.sys vgapnp.sys videoprt.sys framebuf.dll win32k.sys #mermaid-svg-fzItc7sN9Ar6yCdP{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-fzItc7sN9Ar6yCdP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fzItc7sN9Ar6yCdP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fzItc7sN9Ar6yCdP .error-icon{fill:#552222;}#mermaid-svg-fzItc7sN9Ar6yCdP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fzItc7sN9Ar6yCdP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fzItc7sN9Ar6yCdP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fzItc7sN9Ar6yCdP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fzItc7sN9Ar6yCdP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fzItc7sN9Ar6yCdP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fzItc7sN9Ar6yCdP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fzItc7sN9Ar6yCdP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fzItc7sN9Ar6yCdP .marker.cross{stroke:#333333;}#mermaid-svg-fzItc7sN9Ar6yCdP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fzItc7sN9Ar6yCdP p{margin:0;}#mermaid-svg-fzItc7sN9Ar6yCdP .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fzItc7sN9Ar6yCdP text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-fzItc7sN9Ar6yCdP .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-fzItc7sN9Ar6yCdP .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-fzItc7sN9Ar6yCdP .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-fzItc7sN9Ar6yCdP .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-fzItc7sN9Ar6yCdP #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-fzItc7sN9Ar6yCdP .sequenceNumber{fill:white;}#mermaid-svg-fzItc7sN9Ar6yCdP #sequencenumber{fill:#333;}#mermaid-svg-fzItc7sN9Ar6yCdP #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-fzItc7sN9Ar6yCdP .messageText{fill:#333;stroke:none;}#mermaid-svg-fzItc7sN9Ar6yCdP .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fzItc7sN9Ar6yCdP .labelText,#mermaid-svg-fzItc7sN9Ar6yCdP .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-fzItc7sN9Ar6yCdP .loopText,#mermaid-svg-fzItc7sN9Ar6yCdP .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-fzItc7sN9Ar6yCdP .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-fzItc7sN9Ar6yCdP .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-fzItc7sN9Ar6yCdP .noteText,#mermaid-svg-fzItc7sN9Ar6yCdP .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-fzItc7sN9Ar6yCdP .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fzItc7sN9Ar6yCdP .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fzItc7sN9Ar6yCdP .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fzItc7sN9Ar6yCdP .actorPopupMenu{position:absolute;}#mermaid-svg-fzItc7sN9Ar6yCdP .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-fzItc7sN9Ar6yCdP .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fzItc7sN9Ar6yCdP .actor-man circle,#mermaid-svg-fzItc7sN9Ar6yCdP line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-fzItc7sN9Ar6yCdP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 桌面就绪,GDI 软件渲染直写帧缓冲 读注册表 InstalledDisplayDrivers="framebuf"加载 framebuf.dllDrvEnableDriver → 获取 DDI 函数表DrvEnablePDEV (DEVMODEW 指定分辨率)IOCTL_VIDEO_QUERY_NUM_AVAIL_MODESIOCTL_VIDEO_QUERY_AVAIL_MODESGetAvailableModes 过滤 → 选择模式 → 填 GDIINFO/DEVINFODrvCompletePDEV (hDevEng)DrvEnableSurfaceIOCTL_VIDEO_SET_CURRENT_MODEIOCTL_VIDEO_MAP_VIDEO_MEMORY帧缓冲虚拟地址EngCreateBitmap(帧缓冲) + EngAssociateSurface

9.3 运行时渲染路径

#mermaid-svg-VrRukHlODsBvErdC{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-VrRukHlODsBvErdC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VrRukHlODsBvErdC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VrRukHlODsBvErdC .error-icon{fill:#552222;}#mermaid-svg-VrRukHlODsBvErdC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VrRukHlODsBvErdC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VrRukHlODsBvErdC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VrRukHlODsBvErdC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VrRukHlODsBvErdC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VrRukHlODsBvErdC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VrRukHlODsBvErdC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VrRukHlODsBvErdC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VrRukHlODsBvErdC .marker.cross{stroke:#333333;}#mermaid-svg-VrRukHlODsBvErdC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VrRukHlODsBvErdC p{margin:0;}#mermaid-svg-VrRukHlODsBvErdC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VrRukHlODsBvErdC .cluster-label text{fill:#333;}#mermaid-svg-VrRukHlODsBvErdC .cluster-label span{color:#333;}#mermaid-svg-VrRukHlODsBvErdC .cluster-label span p{background-color:transparent;}#mermaid-svg-VrRukHlODsBvErdC .label text,#mermaid-svg-VrRukHlODsBvErdC span{fill:#333;color:#333;}#mermaid-svg-VrRukHlODsBvErdC .node rect,#mermaid-svg-VrRukHlODsBvErdC .node circle,#mermaid-svg-VrRukHlODsBvErdC .node ellipse,#mermaid-svg-VrRukHlODsBvErdC .node polygon,#mermaid-svg-VrRukHlODsBvErdC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VrRukHlODsBvErdC .rough-node .label text,#mermaid-svg-VrRukHlODsBvErdC .node .label text,#mermaid-svg-VrRukHlODsBvErdC .image-shape .label,#mermaid-svg-VrRukHlODsBvErdC .icon-shape .label{text-anchor:middle;}#mermaid-svg-VrRukHlODsBvErdC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VrRukHlODsBvErdC .rough-node .label,#mermaid-svg-VrRukHlODsBvErdC .node .label,#mermaid-svg-VrRukHlODsBvErdC .image-shape .label,#mermaid-svg-VrRukHlODsBvErdC .icon-shape .label{text-align:center;}#mermaid-svg-VrRukHlODsBvErdC .node.clickable{cursor:pointer;}#mermaid-svg-VrRukHlODsBvErdC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VrRukHlODsBvErdC .arrowheadPath{fill:#333333;}#mermaid-svg-VrRukHlODsBvErdC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VrRukHlODsBvErdC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VrRukHlODsBvErdC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VrRukHlODsBvErdC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VrRukHlODsBvErdC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VrRukHlODsBvErdC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VrRukHlODsBvErdC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VrRukHlODsBvErdC .cluster text{fill:#333;}#mermaid-svg-VrRukHlODsBvErdC .cluster span{color:#333;}#mermaid-svg-VrRukHlODsBvErdC 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-VrRukHlODsBvErdC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VrRukHlODsBvErdC rect.text{fill:none;stroke-width:0;}#mermaid-svg-VrRukHlODsBvErdC .icon-shape,#mermaid-svg-VrRukHlODsBvErdC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VrRukHlODsBvErdC .icon-shape p,#mermaid-svg-VrRukHlODsBvErdC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VrRukHlODsBvErdC .icon-shape .label rect,#mermaid-svg-VrRukHlODsBvErdC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VrRukHlODsBvErdC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VrRukHlODsBvErdC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VrRukHlODsBvErdC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 调色板变更
模式切换/全屏
应用程序
gdi32.dll
win32k ntgdi

(对象/裁剪/变换)
GDI 引擎 eng/

(DIB 软件渲染)
framebuf 表面

(EngCreateBitmap 的位图)
帧缓冲内存

(ScreenPtr 直接映射)
VirtualBox 虚拟显卡
DrvSetPalette
DrvAssertMode
IOCTL 下发 CLUT

关键:framebuf 不实现任何绘图 DDI(DrvBitBlt/DrvTextOut 等),全部渲染由 GDI 引擎 DIB 引擎完成,直接写入帧缓冲。 这是"通用帧缓冲"设计------只依赖硬件支持线性帧缓冲,与具体显卡厂商无关。


10. 设计特点总结

  1. 零硬件加速:不实现绘图回调,渲染全部由 GDI 引擎软件完成------最大兼容性,适配所有提供线性帧缓冲的显卡。
  2. 帧缓冲直连EngCreateBitmap(pvBits = ScreenPtr) 让 GDI 引擎直接渲染到硬件显存,无中间拷贝。
  3. 模式过滤严格:只接受 1 平面、图形模式、8/16/24/32bpp。
  4. 双模式调色板:8bpp 索引调色板(含 20 色系统基础色)+ 真彩色位域调色板(PAL_BITFIELDS)。
  5. 软件光标默认 :委托 EngSetPointerShape 由 GDI 引擎绘制;硬件光标为实验性代码(默认关闭)。
  6. DirectDraw 基础支持:提供显存表面创建与主表面信息,使 DirectX 应用可用(通过 reactx 驱动)。
  7. PNP/模式切换完备:DrvAssertMode 支持全屏独占模式切换,DrvGetModes 支持模式枚举。
  8. 依赖最小化:仅导入 win32k(Eng* 服务)与内核库,通过 IOCTL 与 miniport 解耦。

11. 源码索引

文件 关键内容
enable.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/enable.c) DrvFunctionTable、DrvEnableDriver、DrvEnablePDEV、DrvCompletePDEV、DrvDisablePDEV
screen.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/screen.c) GetAvailableModes、IntInitScreenInfo、DrvGetModes、默认字体定义
surface.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/surface.c) DrvEnableSurface、DrvDisableSurface、DrvAssertMode
palette.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/palette.c) BASEPALETTE、IntInitDefaultPalette、IntSetPalette、DrvSetPalette
pointer.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/pointer.c) 软件光标委托、实验性硬件光标(IntShow/HideMousePointer)
dd.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/dd.c) DdCanCreateSurface、DdCreateSurface
ddenable.c(file:///d:/reactos/win32ss/drivers/displays/framebuf/ddenable.c) DrvEnableDirectDraw、DrvGetDirectDrawInfo
framebuf.h(file:///d:/reactos/win32ss/drivers/displays/framebuf/framebuf.h) PDEV 结构、DirectX 支持字段
CMakeLists.txt(file:///d:/reactos/win32ss/drivers/displays/framebuf/CMakeLists.txt) 构建配置(kerneldll,入口 DrvEnableDriver)

关联模块:

  • 视频端口驱动:videoprt/(file:///d:/reactos/win32ss/drivers/videoprt/videoprt.c)(提供 IOCTL 服务)
  • VBE miniport:miniport/vbe/(file:///d:/reactos/win32ss/drivers/miniport/vbe/vbemp.c)(模式/帧缓冲/调色板实际执行)
  • win32k 加载:ntuser/display.c(file:///d:/reactos/win32ss/user/ntuser/display.c)(InstalledDisplayDrivers 指定 framebuf)
  • GDI 引擎软件渲染:win32ss/gdi/eng/(file:///d:/reactos/win32ss/gdi/eng/bitblt.c) 与 win32ss/gdi/dib/(file:///d:/reactos/win32ss/gdi/dib/dib.c)(实际执行像素操作)

本文档基于 ReactOS 源代码 win32ss/drivers/displays/framebuf/ 分析(2026 年 8 月)

相关推荐
M158227690551 小时前
四通道 Profinet 转 Modbus RTU 网关 SG-PN-Modbus_4 全场景落地详解
网络·工控布线
跨境小彭1 小时前
Temu运营优化方案:活动库存自动化管控,解决断流、超卖与权重下跌问题
大数据·运维·人工智能·自动化·跨境电商·temu·temu电商运营
漫谈数据智理1 小时前
IDS-RAM 如何支撑数据空间走向可
大数据·运维·微服务
佳児素花痴╮1 小时前
网络问题与基础理论
运维·服务器·网络
Oflycomm1 小时前
IPC网络摄像机与安防监控:Wi-Fi 6模组、AOV低功耗与边缘AI的产业落地
网络·人工智能·安防监控·wifi6·ipc网络摄像机
0x531 小时前
Java网络编程(四)
java·网络
tanglinS2 小时前
工业陶瓷在半导体设备里都用哪里?氮化铝基板与氮化硅结构件的静电无尘角色
大数据·运维·人工智能·自动化·材质
highreport2 小时前
HighReport报表工具定时调度和邮件定时发送
运维·服务器·数据库
TonyLee0172 小时前
Claude Code + DeepSeek:服务器安装与使用笔记
linux·服务器·deepseek·claude code