ReactOS 图形系统分析(31):内核 GDI --- ntgdi/
1. 概述
ntgdi/ (win32ss/gdi/ntgdi/,53 个文件)是 内核态 GDI(Graphics Device Interface) ------win32k.sys 中直接承接用户态 gdi32.dll/win32u.dll 系统调用的层。它处于架构最核心的位置:
用户态: gdi32.dll(GDI API 包装)→ win32u.dll(NtGdi* 系统调用)
↓
ntgdi/(内核 GDI ← 本分析对象)
├─ NtGdi* 系统调用入口(238 个,31 个文件)
├─ GDI 对象管理(句柄表/引用计数/属性池)
├─ DC 状态机(DC 结构/生命周期/属性/坐标变换)
├─ 裁剪合成(prgnVis/prgnRao/prgnAPI → XCLIPOBJ)
└─ 绘制命令(位块/线/形/文本/路径/区域/调色板/打印/D3D/OpenGL)
↓
gdi/eng/(引擎:DDI 分发 + 软件渲染,见《分析_4~28》)
↓
gdi/dib/ + gdi/diblib/(像素实现,见《分析_29/30》)→ 显示驱动 → 帧缓冲
三大职责:
| 职责 | 说明 |
|---|---|
| 系统调用入口 | 全部 NtGdi*(238 个)在 ntgdi 实现:用户参数探测(ProbeForRead+SEH)、句柄校验、锁 DC,然后转内部 IntGdi*/Gre* |
| GDI 对象管理 | 句柄表(gpentHmgr)、引用计数(gpaulRefCount)、对象锁、属性池------DC/位图/画刷/画笔/字体/调色板/区域/路径的统一生命周期 |
| 绘制状态机 | DC 结构(DC+DCLEVEL+DC_ATTR)、坐标变换(世界→页面→设备)、裁剪区域合成、ROP/混合模式------把"应用请求"翻译成"引擎可执行的表面操作" |
与《分析_4》的关系: 《分析_4》的架构图把 win32k 分为 ntgdi/(内核 GDI:对象管理、DC、系统调用)------本分析正是该层的展开,且与已产出的分册互相对应(见第 9 节)。
2. 系统调用层 --- NtGdi* 入口
2.1 调用机制
gdi32.dll: BitBlt(hdc,...) → NtGdiBitBlt(win32u 转发)
↓ win32k.spec / w32ksvc 表
ntgdi/bitblt.c: NtGdiBitBlt(锁 DC → 取表面 → 内部处理)
↓ IntEngBitBlt(eng,见《分析_4》3.1)
2.2 入口分布(238 个,按文件统计)
| 文件 | NtGdi* 数 | 典型入口 |
|---|---|---|
| d3dkmt.c(file:///d:/reactos/win32ss/gdi/ntgdi/d3dkmt.c) | 55 | NtGdiDdDDI*(D3DKMT 内核接口:Present/Lock/CreateDevice 等) |
| font.c(file:///d:/reactos/win32ss/gdi/ntgdi/font.c) | 17 | NtGdiCreateFontIndirect/NtGdiEnumFonts 等字体枚举/创建 |
| coord.c(file:///d:/reactos/win32ss/gdi/ntgdi/coord.c) | 16 | NtGdiSetWorldTransform/NtGdiGetDeviceCaps 等 |
| palette.c(file:///d:/reactos/win32ss/gdi/ntgdi/palette.c) | 14 | NtGdiCreatePalette/NtGdiRealizePalette |
| bitblt.c(file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c) | 13 | NtGdiBitBlt/NtGdiStretchBlt/NtGdiAlphaBlend/NtGdiFillRgn/NtGdiFrameRgn |
| path.c(file:///d:/reactos/win32ss/gdi/ntgdi/path.c) | 13 | NtGdiBeginPath/NtGdiEndPath/NtGdiStrokePath/NtGdiFillPath |
| region.c(file:///d:/reactos/win32ss/gdi/ntgdi/region.c) | 12 | NtGdiCreateRectRgn/NtGdiCombineRgn/NtGdiPtInRegion |
| dcobjs.c(file:///d:/reactos/win32ss/gdi/ntgdi/dcobjs.c) | 9 | NtGdiCreateDC/NtGdiDeleteDC/NtGdiSaveDC/NtGdiRestoreDC |
| text.c(file:///d:/reactos/win32ss/gdi/ntgdi/text.c) | 8 | NtGdiTextOut/NtGdiGetTextExtent/NtGdiGetTextMetrics |
| bitmaps.c(file:///d:/reactos/win32ss/gdi/ntgdi/bitmaps.c) | 7 | NtGdiCreateBitmap/NtGdiGetBitmapBits/NtGdiSetBitmapBits |
| brush.cpp(file:///d:/reactos/win32ss/gdi/ntgdi/brush.cpp) | 7 | NtGdiCreateSolidBrush/NtGdiCreatePatternBrush |
| fillshap.c(file:///d:/reactos/win32ss/gdi/ntgdi/fillshap.c) | 6 | NtGdiEllipse/NtGdiRoundRect/NtGdiGradientFill/NtGdiFloodFill |
| cliprgn.c(file:///d:/reactos/win32ss/gdi/ntgdi/cliprgn.c) | 6 | NtGdiSelectClipRgn/NtGdiGetClipRgn |
| icm.c(file:///d:/reactos/win32ss/gdi/ntgdi/icm.c) | 6 | NtGdiGetColorSpace/NtGdiCreateColorSpace |
| print.c(file:///d:/reactos/win32ss/gdi/ntgdi/print.c) | 7 | NtGdiResetDC/NtGdiStartDoc/NtGdiStartPage |
| 其余(dcutil/dibobj/gdibatch/arc/dclife/line/pen/metafile/wingl/stockobj/init 等) | ~30 | NtGdiGetPixel/NtGdiCreateDIBitmap/NtGdiFlushUserBatch/NtGdiAngleArc/NtGdiCreatePen 等 |
通用入口模式 (以 NtGdiAlphaBlend(file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c#L13-L131) 为例):DC_LockDc 校验/锁定 → 源目标位图/表面定位 → IntEng* 调引擎 → DC_UnlockDc;用户结构一律 ProbeForRead + _SEH2_TRY 拷贝进内核。
3. GDI 对象管理(gdiobj.c(file:///d:/reactos/win32ss/gdi/ntgdi/gdiobj.c) + gdipool.c(file:///d:/reactos/win32ss/gdi/ntgdi/gdipool.c) + dibobj.c(file:///d:/reactos/win32ss/gdi/ntgdi/dibobj.c))
3.1 句柄表(会话空间共享)
InitGdi(会话初始化)
├─ 句柄表节映射 → gpentHmgr(GDI_HANDLE_COUNT 项,会话共享)
└─ 引用计数表 gpaulRefCount = EngAllocSectionMem(见《分析_23/21》)
- 句柄 = 表索引;
GDIOBJ_AllocObjWithHandle分配、GDIOBJ_ReferenceObjectByHandle取用(带类型校验 + 引用计数gpaulRefCount[idx]原子增减); - 句柄表映射到用户态(
Peb->GdiSharedHandleTable),gdi32 可直接读写共享表优化句柄操作; - 每个对象带
BASEOBJECT头(BaseFlags/hHmgr/pEntry)与类型派生的锁/释放回调(如SURFACE_vCleanup)。
3.2 对象类型
| 对象 | 头文件 | 管理要点 |
|---|---|---|
| DC | dc.h | DCLEVEL 层叠 + DC_ATTR 属性(见第 4 节) |
| 位图 SURFACE | eng/surface.h | hDIBSection/hSecure/dwOffset(DIB Section,见《分析_21/23》) |
| 画刷 BRUSH | brush.h | 逻辑画刷 + 引擎 EBRUSHOBJ 实现(engbrush.c) |
| 画笔 PEN | pen.h | 逻辑笔 + 宽笔判定(line.c) |
| 字体 LFONT/TEXTOBJ | text.h | 字体句柄 + FreeType 实现(freetype.c) |
| 调色板 PALETTE | palette.h | PAL_* 标志(见《分析_19》) |
| 区域 REGION | region.h | 区域数据(RDH/矩形缓冲) |
| 路径 PATH | path.h | pPoints/pFlags + EXTPATHDATA 双表示(见《分析_18》) |
3.3 属性池(gdipool.c)
c
ppiCurrent->pPoolDcAttr = GdiPoolCreate(sizeof(DC_ATTR), 'acdG');
ppiCurrent->pPoolBrushAttr = GdiPoolCreate(sizeof(BRUSH_ATTR), 'arbG');
ppiCurrent->pPoolRgnAttr = GdiPoolCreate(sizeof(RGN_ATTR), 'agrG');
按进程 的固定大小属性对象池(DC 属性/画刷属性/区域属性),避免频繁 EngAllocMem 小对象开销------进程创建时建(init.c GdiProcessCreate),销毁时回收(GdiPoolDestroy)。
3.4 系统对象(stockobj.c)
CreateStockObjects(系统字体/空画笔/黑白画笔等 21 个库存 GDI 对象)+ CreateSysColorObjects(系统颜色画刷)------由 IntGetSysColorBrush 等按索引取用。
4. DC 管理(dcobjs.c(file:///d:/reactos/win32ss/gdi/ntgdi/dcobjs.c) / dclife.c(file:///d:/reactos/win32ss/gdi/ntgdi/dclife.c) / dcstate.c(file:///d:/reactos/win32ss/gdi/ntgdi/dcstate.c) / dcattr.c(file:///d:/reactos/win32ss/gdi/ntgdi/dcattr.c) / dcutil.c(file:///d:/reactos/win32ss/gdi/ntgdi/dcutil.c))
4.1 DC 结构(dc.h(file:///d:/reactos/win32ss/gdi/ntgdi/dc.h))
c
typedef struct _DCLEVEL // 每层保存状态(SaveDC/RestoreDC 压栈)
{
HPALETTE hpal; PPALETTE ppal; PBRUSH pbrFill; PBRUSH pbrLine;
LFONT *plfnt; HGDIOBJ hPath; FLONG flPath;
PREGION prgnClip; COLORADJUSTMENT ca;
MATRIX mxWorldToDevice; MATRIX mxDeviceToWorld; // 变换矩阵
...
} DCLEVEL;
typedef enum { DCTYPE_DIRECT, DCTYPE_MEMORY, DCTYPE_INFO } DCTYPE;
typedef struct _DC { // 完整 DC
BASEOBJECT BaseObject;
DCTYPE dctype; FLONG fs; // DC_DISPLAY/DC_DIRECT 等标志
PDCLEVEL dclevel; // 层叠栈(当前层 + 历史层)
PDC_ATTR pdcattr; // 属性(前景/背景色、ROP2、映射模式...)
SURFACE *pSurface; PSURFACE psurf;
XCLIPOBJ co; // 内嵌裁剪对象
PPDEVOBJ ppdev; // 物理设备(屏幕)
...
} DC, *PDC;
DCLEVEL层叠 :SaveDC压栈 /RestoreDC弹栈,实现 DC 状态保存(含变换/字体/裁剪/画刷);DC_ATTR:常规属性(crBackgroundClr/crForegroundClr/jROP2/jBkMode/iGraphicsMode/ptlCurrent等,见《分析_17》的 MIX 构造);- DCTYPE:DIRECT(设备/屏幕)、MEMORY(内存 DC,选位图)、INFO(信息 DC,只查能力不绘制)。
4.2 生命周期与关键操作
| 文件 | 内容 |
|---|---|
| dcobjs.c | NtGdiCreateDC/NtGdiDeleteDC/NtGdiSaveDC/NtGdiRestoreDC、DC_LockDc 句柄校验 |
| dclife.c | NtGdiOpenDCW(打开设备)、NtGdiCreateCompatibleDC、NtGdiDeleteObjectApp、IntGdiFillRgn 前的裁剪合成 + MouseSafety(见《分析_24》) |
| dcstate.c | DC 状态字段更新/脏标记(DC_vUpdateFillBrush 等) |
| dcattr.c | DC_ATTR 初始化/复制(GdiPool 分配) |
| dcutil.c | IntGdiSetPixel/IntGdiGetPixel(EXLATEOBJ 转色,见《分析_19》)、IntLPtoDP 等工具 |
5. 坐标变换与映射模式(coord.c(file:///d:/reactos/win32ss/gdi/ntgdi/coord.c) + xformobj.c(file:///d:/reactos/win32ss/gdi/ntgdi/xformobj.c) + coord.h(file:///d:/reactos/win32ss/gdi/ntgdi/coord.h))
世界坐标 →(SetWorldTransform) → 页面坐标 →(映射模式 MM_*) → 设备坐标 →(设备原点) → 屏幕
MATRIX mxWorldToDevice / mxDeviceToWorld(FLOATOBJ,见《分析_22》)
- 变换矩阵 :
xformobj.c用FLOATOBJ_XFORM(eM11...eDy)实现SetWorldTransform/CombineTransform/ModifyWorldTransform,coord.h的IntLPtoDP做点乘; - 映射模式 :
coord.c处理 MM_TEXT/MM_ISOTROPIC/MM_ANISOTROPIC/MM_HIMETRIC 等,用EngMulDiv换算 WindowExt/ViewportExt(见《分析_22》); - DC 原点 :
ptlDCOrig偏移在绘制前并入(见《分析_17》IntGdiFillRgn 的 REGION_bOffsetRgn)。
6. 裁剪区域合成(cliprgn.c(file:///d:/reactos/win32ss/gdi/ntgdi/cliprgn.c) + dclife.c)
prgnVis(可见区域) ∩ prgnRao(窗口重定向/系统区) = 有效裁剪
+ prgnAPI(SelectClipRgn 的 API 裁剪)
↓ IntEngInitClipObj + IntEngUpdateClipRegion(dclife.c)
XCLIPOBJ(→ 引擎裁剪枚举,见《分析_4》2.2/3.2)
NtGdiSelectClipRgn 设置 API 裁剪;绘制前 IntGdiFillRgn/IntEngBitBlt 等把三层区域求交合成为 XCLIPOBJ 传给引擎(配合《分析_24》的 MouseSafety 隐藏光标)。
7. 绘制命令子系统
| 子系统 | 文件 | 典型功能 | 引擎对接 |
|---|---|---|---|
| 位图对象 | bitmaps.c(file:///d:/reactos/win32ss/gdi/ntgdi/bitmaps.c) / dibobj.c(file:///d:/reactos/win32ss/gdi/ntgdi/dibobj.c) | CreateBitmap/CreateDIBSection/Get·SetBitmapBits、DIB 位图 | EngCreateBitmap(《分析_21》)、DecompressBitmap(《分析_28》) |
| 位块传输 | bitblt.c(file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c) | BitBlt/StretchBlt/TransparentBlt/AlphaBlend/FillRgn/PaintRgn/FrameRgn | IntEng*(《分析_4/26/27》) |
| 线条 | line.c(file:///d:/reactos/win32ss/gdi/ntgdi/line.c) | LineTo/Polyline/宽笔判定 | IntEngLineTo(《分析_5》) |
| 弧/贝塞尔 | arc.c(file:///d:/reactos/win32ss/gdi/ntgdi/arc.c) / bezier.c(file:///d:/reactos/win32ss/gdi/ntgdi/bezier.c) | Arc/Ellipse/Pie/AngleArc、贝塞尔转折线 | GDI_Bezier → 路径/折线 |
| 形状填充 | fillshap.c(file:///d:/reactos/win32ss/gdi/ntgdi/fillshap.c) / polyfill.c(file:///d:/reactos/win32ss/gdi/ntgdi/polyfill.c) | 椭圆/圆角矩形/GradientFill/FloodFill、多边形 | IntEngGradientFill(《分析_26》)/IntEngFillPolygon |
| 文本 | text.c(file:///d:/reactos/win32ss/gdi/ntgdi/text.c) / freetype.c(file:///d:/reactos/win32ss/gdi/ntgdi/freetype.c) / font.c(file:///d:/reactos/win32ss/gdi/ntgdi/font.c) | TextOut/度量、字形渲染(FreeType→MaskBlt)、字体枚举/资源 | IntExtTextOutW(《分析_16》) |
| 路径 | path.c(file:///d:/reactos/win32ss/gdi/ntgdi/path.c) | BeginPath/EndPath/StrokePath/FillPath/WidenPath | PATH_*(《分析_18》) |
| 区域/矩形 | region.c(file:///d:/reactos/win32ss/gdi/ntgdi/region.c) / rect.c(file:///d:/reactos/win32ss/gdi/ntgdi/rect.c) | 区域布尔运算/命中测试 | IntGdiCombineRgn |
| 画笔/画刷 | pen.c(file:///d:/reactos/win32ss/gdi/ntgdi/pen.c) / brush.cpp(file:///d:/reactos/win32ss/gdi/ntgdi/brush.cpp) | 逻辑笔/画刷创建 | EBRUSHOBJ_vInit(engbrush.c) |
| 调色板/色彩 | palette.c(file:///d:/reactos/win32ss/gdi/ntgdi/palette.c) / icm.c(file:///d:/reactos/win32ss/gdi/ntgdi/icm.c) | 调色板实现/ICM 色彩空间 | EXLATEOBJ(《分析_19》) |
| 打印 | print.c(file:///d:/reactos/win32ss/gdi/ntgdi/print.c) | StartDoc/StartPage/ResetDC/假脱机 | 引擎打印桩(《分析_28》) |
| 元文件 | metafile.c(file:///d:/reactos/win32ss/gdi/ntgdi/metafile.c) | PlayMetaFile 记录回放 | 转普通 GDI 调用 |
| OpenGL | wingl.c(file:///d:/reactos/win32ss/gdi/ntgdi/wingl.c) | SetPixelFormat/SwapBuffers/DescribePixelFormat | 与 D3D/驱动对接 |
| DirectX 内核 | d3dkmt.c(file:///d:/reactos/win32ss/gdi/ntgdi/d3dkmt.c) | 55 个 NtGdiDdDDI*(D3DKMT) |
dxgkrnl/dxg |
| 批处理 | gdibatch.c(file:///d:/reactos/win32ss/gdi/ntgdi/gdibatch.c) | 用户态 GDI 批处理刷出(NtGdiFlushUserBatch) | --- |
| 调试 | gdidbg.c(file:///d:/reactos/win32ss/gdi/ntgdi/gdidbg.c) / gdikdbgext.c | 引擎级 DPRINT/内核调试扩展 | --- |
8. 初始化与生命周期(init.c(file:///d:/reactos/win32ss/gdi/ntgdi/init.c))
| 函数 | 时机 | 内容 |
|---|---|---|
GdiProcessCreate |
每进程创建 | 映射句柄表到 PEB、建 DC/画刷/区域属性池、初始化私有字体链表 |
GdiProcessDestroy |
每进程销毁 | 清理私有字体、回收 GDI 对象与属性池 |
InitializeGreCSRSS |
会话启动(CSRSS 初始化) | DxStartupDxgkInt(Dxgkrnl 接口)、DxDdStartupDxGraphics(DirectX 显示驱动)、InitFontSupport(FreeType) |
NtGdiInit |
每进程 | 简单成功返回(真正的进程初始化在 GdiProcessCreate) |
9. 与《架构分析》及各分册的关系
| 架构图条目 | 对应分册 |
|---|---|
| ntgdi(对象管理/DC/系统调用) | 本分析(31) |
| ntgdi 的线条 | 《分析_5》(line.c/IntGdiLineTo) |
| ntgdi 文本 | 《分析_16》(freetype.c/IntExtTextOutW) |
| ntgdi 渐变/区域填充 | 《分析_17/26》(IntGdiFillRgn/EngGradientFill) |
| ntgdi 路径 | 《分析_18》(PATH_*/path.c) |
| ntgdi 调色板/颜色 | 《分析_19》(EXLATEOBJ/palette.c) |
| ntgdi 设备注册 | 《分析_4》3.4(device.c→eng) |
| 引擎 eng/ | 《分析_4~28》(eng/ 全模块表) |
| DIB 软件渲染 | 《分析_29/30》(gdi/dib + diblib) |
| 显示驱动 | 《分析_3》(framebuf/vga)、《分析_25》(pandisp) |
10. 源码索引
| 文件 | 关键内容 |
|---|---|
| intgdi.h(file:///d:/reactos/win32ss/gdi/ntgdi/intgdi.h) | 内部 API 声明、WIN32_ROP4_TO_ENG_ROP4/FIXUP_ROP2 宏 |
| init.c(file:///d:/reactos/win32ss/gdi/ntgdi/init.c) | GdiProcessCreate/Destroy、InitializeGreCSRSS |
| dc.h(file:///d:/reactos/win32ss/gdi/ntgdi/dc.h) | DC/DCLEVEL/DC_ATTR/DCTYPE 结构 |
| gdiobj.c(file:///d:/reactos/win32ss/gdi/ntgdi/gdiobj.c) / gdiobj.h | 句柄表、引用计数、GDIOBJ_* 对象管理 |
| gdipool.c(file:///d:/reactos/win32ss/gdi/ntgdi/gdipool.c) | DC/画刷/区域属性池 |
| dcobjs.c(file:///d:/reactos/win32ss/gdi/ntgdi/dcobjs.c) / dclife.c / dcstate.c / dcattr.c / dcutil.c | DC 生命周期/裁剪合成/状态/工具 |
| coord.c(file:///d:/reactos/win32ss/gdi/ntgdi/coord.c) / coord.h / xformobj.c(file:///d:/reactos/win32ss/gdi/ntgdi/xformobj.c) | 映射模式/世界变换 |
| cliprgn.c(file:///d:/reactos/win32ss/gdi/ntgdi/cliprgn.c) | API 裁剪 |
| 绘制子系统 | bitblt.c/line.c/arc.c/bezier.c/fillshap.c/polyfill.c/text.c/freetype.c/font.c/path.c/region.c/rect.c/pen.c/brush.cpp/palette.c/icm.c/print.c/metafile.c/wingl.c/d3dkmt.c/gdibatch.c(详见第 7 节表) |
关联模块:
- 下层:gdi/eng(《分析_4~28》)、gdi/dib + diblib(《分析_29/30》)
- 用户态:gdi32.dll / win32u.dll(NtGdi* 转发)
- 同模块:ntuser(窗口/消息,与 DC 的 prgnVis 联动)、reactx(d3dkmt 的 D3D 对接)
本文档基于 ReactOS 源代码
win32ss/gdi/ntgdi/总览分析(2026 年 8 月)