ReactOS 图形系统分析(7):位块传输 — EngBitBlt / IntEngBitBlt / MaskBlt

ReactOS 图形系统分析(7):位块传输 --- EngBitBlt / IntEngBitBlt / MaskBlt

1. 概述

**位块传输(BitBlt)**是 GDI 引擎(win32ss/gdi/eng/bitblt.c)最核心、最复杂的操作,负责把像素块从一个表面复制/合并到另一个表面,支持 256 种 ROP(光栅操作)组合、源/图案/掩码/裁剪任意组合。BitBltStretchBltMaskBltPatBltAlphaBlend 等 API 最终都汇入本模块。

源码警告(bitblt.c 头部注释(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L10-L12)):

WARNING: Modify this file with extreme caution. It is very sensitive to timing changes. Adding code can cause the system to show a Fatal Exception Error and fail to boot!

该文件对时序极其敏感(在 CallDibBitBltIntEngBitBltEngBitBlt 中即使加 DPRINT 也可能导致启动失败)------是 win32k 中最脆弱的代码之一。

1.1 函数清单

函数 层级 功能
NtGdiEngBitBlt 系统调用入口 SEH 探针拷贝用户参数 → EngBitBlt
IntEngBitBlt 引擎内部 裁剪/源矩形修正 + HOOK 决策(驱动 or 软件)
EngBitBlt 引擎软件实现 ROP4 分析 + 裁剪枚举 + 分发到矩形绘制函数
BltMask 内部 掩码逐像素传输(1bpp 掩码决定前景/背景 ROP)
BltPatCopy 内部 图案拷贝(纯色填充)
CallDibBitBlt 内部 构造 BLTINFO 分发到 DIB 函数表
EngMaskBitBlt 内部 掩码位块(裁剪 + 分发到 BltMask/AlphaBltMask)
IntEngMaskBlt 引擎内部 MaskBlt 入口(1bpp→BitBlt 快路径,8bpp→临时表面)
AlphaBltMask 内部 8bpp 掩码的 Alpha 混合绘制
gxcoTrivial 全局 平凡裁剪对象(全矩形、DC_TRIVIAL)

2. 全局对象 --- gxcoTrivial

c 复制代码
XCLIPOBJ gxcoTrivial =
{
    /* CLIPOBJ 部分 */
    {
        0,  /* iUniq */
        {LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX},  /* rclBounds: 全矩形 */
        DC_TRIVIAL,   /* iDComplexity: 无裁剪 */
        FC_RECT,      /* iFComplexity */
        TC_RECTANGLES,/* iMode */
        0             /* fjOptions */
    },
    /* RWNDOBJ + XCLIPOBJ 私有部分全 0 */
};

当无裁剪对象时,引擎用 gxcoTrivialDC_TRIVIAL)代替------表示"全矩形,无需裁剪"。


3. 层次架构

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

(Hook 决策)
EngBitBlt

(软件实现)
BltMask / BltPatCopy / CallDibBitBlt
IntEngMaskBlt → EngMaskBitBlt
AlphaBltMask (8bpp alpha)
DrvBitBlt (硬件)
DibFunctionsForBitmapFormat

(DIB 引擎)
像素写入表面/显存


4. 核心函数深入分析

4.1 系统调用入口 --- NtGdiEngBitBlt

c 复制代码
BOOL APIENTRY NtGdiEngBitBlt(SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask,
                             CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclTrg,
                             POINTL *pptlSrc, POINTL *pptlMask,
                             BRUSHOBJ *pbo, POINTL *pptlBrush, ROP4 Rop4)
{
    /* SEH 保护:探针并拷贝用户模式参数 */
    _SEH2_TRY
    {
        ProbeForRead(prclTrg, sizeof(RECTL), 1);
        RtlCopyMemory(&rclTrg, prclTrg, sizeof(RECTL));
        ProbeForRead(pptlSrc, sizeof(POINTL), 1);   // 同样处理其余指针
        ...
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
        _SEH2_YIELD(return FALSE);
    }
    _SEH2_END;

    return EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg,
                     &ptlSrc, &ptlMask, pbo, &ptlBrush, Rop4);
}

要点: 所有用户指针先 ProbeForRead + 拷贝到栈上,防止驱动访问时页错误。

4.2 IntEngBitBlt --- 设备挂钩决策(引擎内部主入口)

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







IntEngBitBlt
目标矩形裁剪到表面尺寸
与 pco->rclBounds 求交
pco 复杂度 == DC_RECT?
pco = NULL (去裁剪化)
ROP4 用源?
源矩形裁剪 + 目标修正
psoSrc = NULL
目标表面

HOOK_BITBLT?
pfnBitBlt = GDIDEVFUNCS(目标).BitBlt
源表面

HOOK_BITBLT?
pfnBitBlt = GDIDEVFUNCS(源).BitBlt
pfnBitBlt = EngBitBlt
翻转修正 → 调用 pfnBitBlt

关键代码:

c 复制代码
/* 目标/源表面是否挂钩驱动 DrvBitBlt? */
if (psurfTrg->flags & HOOK_BITBLT)
    pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt;    // 调硬件加速
else if (psoSrc && psurfSrc->flags & HOOK_BITBLT)
    pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt;
else
    pfnBitBlt = EngBitBlt;                     // 软件渲染

4.3 EngBitBlt --- 软件实现(裁剪分析 + 矩形分发)

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




EngBitBlt 入口
ROP4 分析

UsesSource / UsesMask

翻转方向检测
规范化目标矩形
源矩形裁剪

(防越界)
与裁剪边界求交
裁剪复杂度
恢复翻转

直接调用 BltRectFunc
与裁剪矩形求交

调用一次 BltRectFunc
CLIPOBJ_cEnumStart

CLIPOBJ_bEnum 循环

逐矩形求交调用
BltRectFunc 选择
UsesMask?
BltMask
PATCOPY 且纯色?
BltPatCopy

DIB_ColorFill
CallDibBitBlt

DIB_BitBlt
像素级输出

BltRectFunc 选择逻辑:

c 复制代码
typedef BOOLEAN (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj, SURFOBJ* InputObj,
                                         SURFOBJ* Mask, XLATEOBJ* ColorTranslation,
                                         RECTL* OutputRect, POINTL* InputPoint,
                                         POINTL* MaskOrigin, BRUSHOBJ* pbo,
                                         POINTL* BrushOrigin, ROP4 Rop4);

if (UsesMask)
    BltRectFunc = BltMask;                       // ① 掩码传输
else if ((rop4 & 0xFF) == R3_OPINDEX_PATCOPY && pbo && pbo->iSolidColor != 0xFFFFFFFF)
    BltRectFunc = BltPatCopy;                    // ② 纯色图案填充
else
    BltRectFunc = CallDibBitBlt;                 // ③ 通用 DIB 传输

4.4 三个矩形绘制函数

① BltMask --- 掩码逐像素传输

对掩码(必须 BMF_1BPP)逐位判断用前景 ROP 还是背景 ROP:

c 复制代码
static BOOLEAN APIENTRY BltMask(psoDest, psoSource, psoMask, ColorTranslation,
                                prclDest, pptlSource, pptlMask, pbo, pptlBrush, Rop4)
{
    fgndRop   = ROP4_FGND(Rop4);   // 前景 ROP(掩码位=1)
    bkgndRop  = ROP4_BKGND(Rop4);  // 背景 ROP(掩码位=0)

    /* 图案画刷初始化(非纯色时取图案表面) */
    if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
        psoPattern = BRUSHOBJ_psoPattern(pbo);

    /* 掩码指针定位:第 pptlMask->y 行 + 第 pptlMask->x/8 字节 */
    pjMskLine = (PBYTE)psoMask->pvScan0 + pptlMask->y * psoMask->lDelta
                + (pptlMask->x >> 3);
    fjMaskBit0 = 0x80 >> (pptlMask->x & 0x07);   // 起始掩码位

    for (y = prclDest->top; y < prclDest->bottom; y++)
    {
        pjMskCurrent = pjMskLine;
        fjMaskBit = fjMaskBit0;

        for (x = prclDest->left; x < prclDest->right; x++)
        {
            /* 掩码位决定使用前景还是背景 ROP */
            Rop4 = (*pjMskCurrent & fjMaskBit) ? fgndRop : bkgndRop;

            /* 需要时取图案像素(含平移取模) */
            if (ROP4_USES_PATTERN(Rop4))
                Pattern = fnPattern_GetPixel(psoPattern, PatternX, PatternY);

            /* 需要时取源像素并颜色转换 */
            if (ROP4_USES_SOURCE(Rop4))
                Source = XLATEOBJ_iXlate(ColorTranslation,
                                         fnSrc_GetPixel(psoSource, SrcX, SrcY));

            /* 需要时读目标像素 */
            if (ROP4_USES_DEST(Rop4))
                Dest = fnDest_GetPixel(psoDest, x, y);

            /* 计算 ROP 结果并写入 */
            fnDest_PutPixel(psoDest, x, y,
                            DIB_DoRop(Rop4, Dest, Source, Pattern));

            /* 掩码位右移,跨字节时推进指针 */
            fjMaskBit = _rotr8(fjMaskBit, 1);
            pjMskCurrent += (fjMaskBit >> 7);
        }
        pjMskLine += psoMask->lDelta;   // 下一行
    }
}

要点: 这是最通用但最慢 的路径------逐像素调用 GetPixel/PutPixel + DIB_DoRop 软计算 256 种 ROP。

② BltPatCopy --- 纯色图案填充
c 复制代码
static BOOLEAN APIENTRY BltPatCopy(Dest, Source, Mask, ColorTranslation,
                                   DestRect, SourcePoint, MaskPoint,
                                   pbo, BrushPoint, Rop4)
{
    /* 直接调用 DIB 颜色填充(整块一次性) */
    DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(
        Dest, DestRect, pbo ? pbo->iSolidColor : 0);
    return TRUE;
}
③ CallDibBitBlt --- DIB 分发
c 复制代码
static BOOLEAN APIENTRY CallDibBitBlt(OutputObj, InputObj, Mask, ColorTranslation,
                                      OutputRect, InputPoint, MaskOrigin,
                                      pbo, BrushOrigin, Rop4)
{
    BLTINFO BltInfo;

    BltInfo.DestSurface = OutputObj;
    BltInfo.SourceSurface = InputObj;
    BltInfo.PatternSurface = NULL;
    BltInfo.XlateSourceToDest = ColorTranslation;
    BltInfo.DestRect = *OutputRect;
    BltInfo.SourcePoint = *InputPoint;

    /* SRCCOPY 快路径:直接调 DIB_BitBltSrcCopy(批量拷贝) */
    if ((Rop4 & 0xFF) == R3_OPINDEX_SRCCOPY)
        return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat]
                                          .DIB_BitBltSrcCopy(&BltInfo);

    BltInfo.Brush = pbo;
    BltInfo.BrushOrigin = *BrushOrigin;
    BltInfo.Rop4 = Rop4;

    /* 图案画刷:iSolidColor == 0xFFFFFFFF 表示非纯色,取图案表面 */
    if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
        BltInfo.PatternSurface = BRUSHOBJ_psoPattern(pbo);

    RECTL_vMakeWellOrdered(&BltInfo.DestRect);

    return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat]
                                      .DIB_BitBlt(&BltInfo);
}

4.5 MaskBlt --- IntEngMaskBlt / EngMaskBitBlt

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



IntEngMaskBlt
掩码是 BMF_1BPP?
IntEngBitBlt(psoMask, ROP4_MASKPAINT)

(复用 BitBlt 快路径)
断言 BMF_8BPP

(alpha 掩码)
与裁剪边界求交

调整掩码原点
目标表面是

STYPE_BITMAP?
分配临时表面 SURFACE_AllocSurface
EngCopyBits 拷贝目标区域

到临时表面
EngMaskBitBlt(临时表面)
EngCopyBits 写回目标表面

(带裁剪)
删除临时表面
直接 EngMaskBitBlt(目标)
返回结果

1bpp 掩码快路径: 掩码为 1 位/像素时直接调用 IntEngBitBlt 并指定 ROP4_MASKPAINT(前景 PATCOPY / 背景 NOOP),复用优化后的 BitBlt 管线。

8bpp alpha 掩码: 调用 EngMaskBitBlt,按裁剪复杂度分发:

  • DC_TRIVIAL / DC_RECT / DC_COMPLEXAlphaBltMask(逐像素 alpha 混合)或 BltMask(1bpp 时)
  • 目标为设备表面时先用临时位图IntEngEnter 机制),完成后 EngCopyBits 写回

4.6 AlphaBltMask --- 8bpp Alpha 混合

c 复制代码
static BOOL APIENTRY AlphaBltMask(psoDest, psoSource, psoMask, pxloRGB2Dest,
                                  pxloBrush, prclDest, pptlSource, pptlMask,
                                  pbo, pptlBrush)
{
    /* 画刷颜色(经 XLATE 转换后取 RGB 分量) */
    BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo->iSolidColor);
    r = GetRValue(BrushColor); g = GetGValue(BrushColor); b = GetBValue(BrushColor);

    for (j = 0; j < dy; j++)
        for (i = 0; i < dx; i++)
        {
            if (*lMask > 0)
            {
                if (*lMask == 0xff)
                    /* 完全不透明:直接写画刷色 */
                    DIB_PutPixel(psoDest, x, y, pbo->iSolidColor);
                else
                {
                    /* 部分透明:按掩码值线性插值 */
                    Background = DIB_GetSource(psoDest, x, y, pxloBrush);
                    NewColor = RGB((*lMask * (r - Rb) >> 8) + Rb,
                                   (*lMask * (g - Gb) >> 8) + Gb,
                                   (*lMask * (b - Bb) >> 8) + Bb);
                    DIB_PutPixel(psoDest, x, y, XLATEOBJ_iXlate(pxloRGB2Dest, NewColor));
                }
            }
        }
}

混合公式: NewColor = (α × 画刷色 + (255-α) × 背景色) / 255,其中 α 为掩码值(0~255)。

4.7 DIB_PutPixel 的实现方式

上面的 DIB_PutPixel 不是一个具体函数,而是 DibFunctionsForBitmapFormat(file:///d:/reactos/win32ss/gdi/dib/dib.c#L20-L88) 函数表中的函数指针 ------引擎按目标表面的 iBitmapFormat 从表中取出对应位深的实现后调用:

c 复制代码
DIB_FUNCTIONS DibFunctionsForBitmapFormat[] =
{
    /* 0: 无效格式 */
    { Dummy_PutPixel, Dummy_GetPixel, ... },
    /* BMF_1BPP */ { DIB_1BPP_PutPixel, DIB_1BPP_GetPixel, ... },
    /* BMF_4BPP */ { DIB_4BPP_PutPixel, DIB_4BPP_GetPixel, ... },
    /* BMF_8BPP */ { DIB_8BPP_PutPixel, DIB_8BPP_GetPixel, ... },
    /* BMF_16BPP */{ DIB_16BPP_PutPixel, DIB_16BPP_GetPixel, ... },
    /* BMF_24BPP */{ DIB_24BPP_PutPixel, DIB_24BPP_GetPixel, ... },
    /* BMF_32BPP */{ DIB_32BPP_PutPixel, DIB_32BPP_GetPixel, ... },
    ...
};

调用时引擎写作 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(psoDest, x, y, Pixel)。各位深实现分布在 gdi/dib/dib*.c 中,本质都是按像素寻址公式计算地址后直接写内存

各位深实现对比
c 复制代码
/* BMF_1BPP --- 位操作(1 字节存 8 像素) */
DIB_1BPP_PutPixel(SurfObj, x, y, c)
{
   addr = pvScan0 + y*lDelta + (x >> 3);        // 字节地址
   if (0 == (c & 0x01)) *addr &= ~MASK1BPP(x);  // 清位
   else                 *addr |=  MASK1BPP(x);  // 置位
}

/* BMF_4BPP --- 半字节操作(1 字节存 2 像素) */
DIB_4BPP_PutPixel(SurfObj, x, y, c)
{
   addr = pvScan0 + (x >> 1) + y*lDelta;        // 字节地址
   *addr = (*addr & notmask[x&1]) |             // 清半字节
           (BYTE)(c << ((1-(x&1))<<2));         // 置半字节(高低四位)
}

/* BMF_8BPP --- 直接写字节 */
DIB_8BPP_PutPixel(SurfObj, x, y, c)
{
   byteaddr = pvScan0 + y*lDelta + x;           // 1 字节/像素
   *byteaddr = (BYTE)c;
}

/* BMF_16BPP --- 直接写字(1 字 = 1 像素) */
DIB_16BPP_PutPixel(SurfObj, x, y, c)
{
   byteaddr = pvScan0 + y*lDelta;
   PWORD addr = (PWORD)byteaddr + x;            // 2 字节/像素
   *addr = (WORD)c;
}

/* BMF_24BPP --- 3 字节:低 2 字节 + 高 1 字节 */
DIB_24BPP_PutPixel(SurfObj, x, y, c)
{
   addr = pvScan0 + y*lDelta + (x<<1) + x;      // 3 字节/像素
   *(PUSHORT)(addr) = c & 0xFFFF;               // 低 16 位(B+G)
   *(addr + 2) = (c >> 16) & 0xFF;              // 高 8 位(R)
}

/* BMF_32BPP --- 直接写字(1 dword = 1 像素) */
DIB_32BPP_PutPixel(SurfObj, x, y, c)
{
   byteaddr = pvScan0 + y*lDelta;
   PDWORD addr = (PDWORD)byteaddr + x;          // 4 字节/像素
   *addr = c;
}
调用链与寻址

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

其他引擎函数
DibFunctionsForBitmapFormat

iBitmapFormat.DIB_PutPixel
位深分支
DIB_32BPP_PutPixel

addr = pvScan0 + y*lDelta + x*4

*(PDWORD)addr = c
DIB_24BPP_PutPixel

3 字节 BGR 顺序写入
DIB_16BPP_PutPixel

*(PWORD)addr = (WORD)c
DIB_8BPP_PutPixel

*(PBYTE)addr = (BYTE)c
DIB_4BPP_PutPixel

半字节读-改-写
DIB_1BPP_PutPixel

位读-改-写
目标表面内存

(帧缓冲/位图)

核心要点:

  1. 函数指针分发表 :引擎通过 iBitmapFormat 索引函数表,把"写一个像素"抽象为统一接口,各位深实现内部完全独立。
  2. 统一寻址公式 :所有实现都基于 pvScan0 + y×lDelta 定位行首,再按位深偏移列------与《ReactOS 图形系统分析_3.md》1.2 节描述的像素布局一致。
  3. ≤4bpp 需要读-改-写:1/4bpp 一个字节含多个像素,写入必须先读原字节、按掩码修改目标位/半字节再写回。
  4. ≥8bpp 直接覆盖:8/16/32bpp 一个像素正好占 1/2/4 字节,可直接写入;24bpp 拆成低 2 字节 + 高 1 字节。
  5. 性能含义 :逐像素 PutPixel 是最慢路径(每像素一次函数指针间接调用),引擎只在无法批量时才用它------批量场景走 DIB_HLine/DIB_VLine/DIB_BitBlt

5. 完整数据流图(一次 BitBlt 的旅程)

#mermaid-svg-5sZQweeJTsCno5LB{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-5sZQweeJTsCno5LB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5sZQweeJTsCno5LB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5sZQweeJTsCno5LB .error-icon{fill:#552222;}#mermaid-svg-5sZQweeJTsCno5LB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5sZQweeJTsCno5LB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5sZQweeJTsCno5LB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5sZQweeJTsCno5LB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5sZQweeJTsCno5LB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5sZQweeJTsCno5LB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5sZQweeJTsCno5LB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5sZQweeJTsCno5LB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5sZQweeJTsCno5LB .marker.cross{stroke:#333333;}#mermaid-svg-5sZQweeJTsCno5LB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5sZQweeJTsCno5LB p{margin:0;}#mermaid-svg-5sZQweeJTsCno5LB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5sZQweeJTsCno5LB .cluster-label text{fill:#333;}#mermaid-svg-5sZQweeJTsCno5LB .cluster-label span{color:#333;}#mermaid-svg-5sZQweeJTsCno5LB .cluster-label span p{background-color:transparent;}#mermaid-svg-5sZQweeJTsCno5LB .label text,#mermaid-svg-5sZQweeJTsCno5LB span{fill:#333;color:#333;}#mermaid-svg-5sZQweeJTsCno5LB .node rect,#mermaid-svg-5sZQweeJTsCno5LB .node circle,#mermaid-svg-5sZQweeJTsCno5LB .node ellipse,#mermaid-svg-5sZQweeJTsCno5LB .node polygon,#mermaid-svg-5sZQweeJTsCno5LB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5sZQweeJTsCno5LB .rough-node .label text,#mermaid-svg-5sZQweeJTsCno5LB .node .label text,#mermaid-svg-5sZQweeJTsCno5LB .image-shape .label,#mermaid-svg-5sZQweeJTsCno5LB .icon-shape .label{text-anchor:middle;}#mermaid-svg-5sZQweeJTsCno5LB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5sZQweeJTsCno5LB .rough-node .label,#mermaid-svg-5sZQweeJTsCno5LB .node .label,#mermaid-svg-5sZQweeJTsCno5LB .image-shape .label,#mermaid-svg-5sZQweeJTsCno5LB .icon-shape .label{text-align:center;}#mermaid-svg-5sZQweeJTsCno5LB .node.clickable{cursor:pointer;}#mermaid-svg-5sZQweeJTsCno5LB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5sZQweeJTsCno5LB .arrowheadPath{fill:#333333;}#mermaid-svg-5sZQweeJTsCno5LB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5sZQweeJTsCno5LB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5sZQweeJTsCno5LB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5sZQweeJTsCno5LB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5sZQweeJTsCno5LB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5sZQweeJTsCno5LB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5sZQweeJTsCno5LB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5sZQweeJTsCno5LB .cluster text{fill:#333;}#mermaid-svg-5sZQweeJTsCno5LB .cluster span{color:#333;}#mermaid-svg-5sZQweeJTsCno5LB 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-5sZQweeJTsCno5LB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5sZQweeJTsCno5LB rect.text{fill:none;stroke-width:0;}#mermaid-svg-5sZQweeJTsCno5LB .icon-shape,#mermaid-svg-5sZQweeJTsCno5LB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5sZQweeJTsCno5LB .icon-shape p,#mermaid-svg-5sZQweeJTsCno5LB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5sZQweeJTsCno5LB .icon-shape .label rect,#mermaid-svg-5sZQweeJTsCno5LB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5sZQweeJTsCno5LB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5sZQweeJTsCno5LB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5sZQweeJTsCno5LB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输出
gdi/dib/
eng/bitblt.c
ntgdi/bitblt.c
gdi32.dll
应用程序
目标表面 HOOK_BITBLT
软件
SRCCOPY
其他 ROP
BitBlt(hdc, ..., SRCCOPY)
GdiBitBlt → NtGdiBitBlt
NtGdiBitBlt

DC/坐标/裁剪区域合成
IntEngBitBlt

(源裁剪+HOOK决策)
EngBitBlt

(ROP4分析+裁剪枚举)
CallDibBitBlt

BLTINFO 构造
DIB_BitBltSrcCopy

(SRCCOPY 快路径)
DIB_32BPP_BitBlt 等

(按位深)
目标表面像素

(帧缓冲/内存位图)
DrvBitBlt (硬件)


6. 设计特点总结

  1. 三级分发NtGdiEngBitBlt(参数探针)→ IntEngBitBlt(HOOK 决策)→ EngBitBlt(裁剪+矩形分发)→ BltMask/BltPatCopy/CallDibBitBlt → DIB 函数表,层次分明。
  2. HOOK 回退原则 :目标/源表面挂钩 DrvBitBlt 才调用驱动,否则软件实现------与引擎其他操作一致。
  3. 裁剪复杂度分级:TRIVIAL/RECT/COMPLEX 三种策略(直接/单次求交/矩形枚举),简单场景零开销。
  4. 矩形绘制函数按需选择:掩码用 BltMask、纯色 PATCOPY 用 BltPatCopy(整块 ColorFill)、其余 CallDibBitBlt------避免统一逐像素。
  5. SRCCOPY 快路径 :最常用的 ROP 单独走 DIB_BitBltSrcCopy 批量内存拷贝。
  6. MaskBlt 双层设计:1bpp 掩码复用 BitBlt 管线(ROP4_MASKPAINT);8bpp 掩码走逐像素 alpha 混合。
  7. 设备表面透明化IntEngEnter + 临时位图 + EngCopyBits 使逐像素渲染适用于无线性帧缓冲的驱动表面。
  8. ROP4 输入分析ROP4_USES_SOURCE/PATTERN/DEST/MASK 宏判断操作依赖,提前剪裁不必要表面、避免无谓读取。
  9. 时序敏感:文件头部明确警告该代码对时序极敏感,改动需极其谨慎(曾导致无法启动)。

7. 源码索引

位置 关键内容
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L20-L33) gxcoTrivial 平凡裁剪对象
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L35-L44) PBLTRECTFUNC 函数指针类型
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L46-L191) BltMask 掩码逐像素传输
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L195-L273) BltPatCopy、CallDibBitBlt
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L281-L322) NtGdiEngBitBlt 系统调用入口
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L327-L654) EngBitBlt 软件实现
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L656-L814) IntEngBitBlt HOOK 决策
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L820-L890) AlphaBltMask
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L892-L1100) EngMaskBitBlt
bitblt.c(file:///d:/reactos/win32ss/gdi/eng/bitblt.c#L1102-L1240) IntEngMaskBlt
dib/dib.c(file:///d:/reactos/win32ss/gdi/dib/dib.c) DIB_DoRop(256 种 ROP 软实现)、DibFunctionsForBitmapFormat
inteng.h(file:///d:/reactos/win32ss/gdi/eng/inteng.h) ROP4 分析宏(ROP4_USES_*)

关联文档:

  • 《ReactOS 图形系统分析_4.md》--- GDI 引擎整体架构(本文件是其 BitBlt 子模块的深入分析)
  • 《ReactOS 图形系统分析_5.md》--- 线条绘制(IntEngLineTo,与 BitBlt 共享裁剪/IntEngEnter 机制)
  • 《ReactOS 图形系统分析_6.md》--- 表面管理(SURFACE 提供 BitBlt 操作对象)
  • ReactOS图形系统架构分析.md》--- DIB 引擎与渲染管线

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

相关推荐
小绫网络安全7 小时前
Kali Linux渗透测试入门教程:从零搭建到实战攻防
linux·运维·服务器
西安景驰电子7 小时前
《PTP精确时间协议系列》第一篇:从原理到应用,全面解读IEEE 1588
linux·运维·服务器·开发语言·网络·windows·php
luj_17687 小时前
塔防牌:策略与卡牌的智慧碰撞
服务器·c语言·开发语言·经验分享·算法
水无痕simon7 小时前
3 短信应用场景以及平台架构
java·服务器
ZGi.ai7 小时前
多模型回答不稳定:路由规则与评测方法
网络·人工智能·大模型评测·多模型·模型路由·zgi·模型网关
80s7778 小时前
独享住宅IP、长效代理ip是什么?有哪些作用?
网络·网络协议·tcp/ip
IPdodo_8 小时前
静态 IP、住宅 IP 和固定出口有什么区别?开发场景选型指南
服务器·网络·网络协议·tcp/ip·代理ip
_ZHOURUI_H_9 小时前
Unity TCP底层极限拆解:粘包、半包、CRC、序列号、双缓冲到底怎么一起工作的?
网络·网络协议·tcp/ip·游戏·unity·游戏引擎·游戏开发
wavemap9 小时前
HyperPHP 免费主机无限流量
服务器·php
Forever Nore9 小时前
LeetCode 13 罗马数字转整数 - 按规则处理
linux·服务器·leetcode