ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ReactOS 图形系统分析(26):Alpha 混合与渐变填充 — alphablend.c / gradient.c

ReactOS 图形系统分析(26):Alpha 混合与渐变填充 — alphablend.c / gradient.c ReactOS 图形系统分析26Alpha 混合与渐变填充 — alphablend.c / gradient.c1. 概述alphablend.c与gradient.c位于win32ss/gdi/eng/是引擎的合成类软件渲染文件功能核心函数[alphablend.c](file:///d:/reactos/win32ss/gdi/eng/alphablend.c)Alpha 混合半透明叠加AlphaBlendAPI 的内核实现EngAlphaBlend/IntEngAlphaBlend/NtGdiEngAlphaBlend[gradient.c](file:///d:/reactos/win32ss/gdi/eng/gradient.c)渐变填充顶点色插值GradientFillAPI 的内核实现EngGradientFill/IntEngGradientFill/IntEngGradientFillRect/IntEngGradientFillTriangle二者共享同一条引擎渲染范式应用 AlphaBlend/GradientFill ↓ gdi32 → NtGdiAlphaBlend / NtGdiGradientFill ntgdibitblt.c / fillshap.cDC 处理、探测拷贝顶点/网格 ↓ IntEngAlphaBlend / IntEngGradientFill驱动挂钩优先 目标表面 HOOK_ALPHABLEND / HOOK_GRADIENTFILL ? → DrvAlphaBlend / DrvGradientFill 否则 ↓ EngAlphaBlend / EngGradientFill ├─ 参数校验矩形规范化/模式/越界/重叠 ├─ IntEngEnter/Leave设备表面 → 临时位图见《分析_25》7.1 ├─ 裁剪三档分发DC_TRIVIAL / DC_RECT / DC_COMPLEX └─ DIB 函数表逐像素/逐线实现DIB_AlphaBlend / DIB_HLine / DIB_VLine / DIB_PutPixel1.1 为什么需要这些功能设计动机AlphaBlend 为什么需要GDI 的透明补课传统 GDI 只支持不透明复制SRCCOPY“与1 位掩码抠图TransparentBlt”无法表达半透明。而 Windows 2000 的现代 UI 全面依赖半透明——分层窗口Layered Window、alpha 光标、阴影/淡入淡出效果全部建立在AlphaBlendAPI 的AC_SRC_OVER混合之上。DDI 契约要求引擎兜底AlphaBlend是 Win2K 起的标准 API其内核实现必须存在但 framebuf 等显示驱动没有硬件 alpha 混合能力引擎必须提供纯软件实现否则这些 API 在绝大多数驱动上无法工作。语义要求严格AC_SRC_OVER源覆盖 可选AC_SRC_ALPHA逐像素 alpha 整体SourceConstantAlpha的混合公式是 Windows 的公开契约引擎实现必须逐位精确——这就是EngAlphaBlend大量参数校验的原因见 2.1。GradientFill 为什么需要现代 UI 的渐变需求GradientFillAPI矩形/三角形渐变用于标题栏渐变、进度条、按钮高光、图表着色等。它把每像素颜色的复杂计算抽象成只给顶点颜色的简单接口由内核负责插值。无浮点环境下的高效插值内核态 x86 不能依赖 FPU见《分析_22》逐像素浮点插值既慢又不确定——因此 gradient.c 用Bresenham 式 DDA误差累计整数插值在颜色端点间线性步进每像素只有加减与比较ec dc; while (ec0) { cic; ec-dy; }既快又无精度漂移。单色快速路径绝大多数实际调用中渐变矩形/三角形的两/三个顶点颜色相同实际是纯色填充插值毫无意义——所以两个渲染器都先判断VCMPCLRS等条件同色直接走纯色填充快路径避免无谓的逐像素插值开销。两者的共同设计约束约束应对目标表面可能是设备管理表面无像素缓冲IntEngEnter/Leave换临时位图 DrvCopyBits往返《分析_25》7.1驱动可能硬件加速vga 的显卡混合/填充HOOK_ALPHABLEND/HOOK_GRADIENTFILL→DrvAlphaBlend/DrvGradientFill优先引擎软件兜底裁剪可能很复杂裁剪三档分发TRIVIAL 一次整块 / RECT 单矩形求交 / COMPLEX 枚举矩形逐块颜色要写进任意位深表面统一经XLATEOBJ_iXlate《分析_19》转换后交给 DIB 函数表按位深实现一句话总结这两个功能是现代 UI 的半透明/渐变需求与引擎必须为无硬件加速驱动提供精确软件实现共同催生的引擎合成层——它们用 DDA 整数插值绕开浮点、用 HOOK 分发优先硬件、用 IntEngEnter 兼容设备表面是引擎渲染范式的典型代表。2. Alpha 混合 — alphablend.c2.1 EngAlphaBlend — 主流程BOOLEngAlphaBlend(psoDest,psoSource,ClipRegion,ColorTranslation,DestRect,SourceRect,BlendObj){/* ① 参数校验 */RECTL_vMakeWellOrdered(OutputRect);// 目标矩形规范化RECTL_vMakeWellOrdered(InputRect);// 源矩形规范化if(源矩形越出源表面)returnFALSE;// 非法输入if(psoDestpsoSource源目标重叠)returnFALSE;if(BlendOp!AC_SRC_OVER)returnFALSE;// 只支持 SRC_OVERif(BlendFlags!0)returnFALSE;if(AlphaFormat~AC_SRC_ALPHA)returnFALSE;// 只允许逐像素 alpha/* ② 设备表面 → 临时位图读源 / 写目标 */IntEngEnter(es,psoSource,InputRect,TRUE,Translate,InputObj);IntEngEnter(ed,psoDest,OutputRect,FALSE,Translate,OutputObj);/* ③ 裁剪三档分发 */switch(ClippingType){caseDC_TRIVIAL:/* 无裁剪一次混合整块 */DIB_AlphaBlend(OutputObj,InputObj,OutputRect,InputRect,...);break;caseDC_RECT:/* 单矩形求交 按比例换算源矩形 */RECTL_bIntersectRect(CombinedRect,OutputRect,ClipRect);Rect按(Combined/Output)比例缩放 InputRect;DIB_AlphaBlend(OutputObj,InputObj,CombinedRect,Rect,...);break;caseDC_COMPLEX:/* 复杂区域枚举矩形逐块混合 */CLIPOBJ_cEnumStartCLIPOBJ_bEnum 循环逐块同 DC_RECT 处理;break;}IntEngLeave(ed);IntEngLeave(es);}关键细节只支持AC_SRC_OVER 可选AC_SRC_ALPHA逐像素 alpha不支持其他 BlendOp如 AC_SRC_ALPHA 之外格式、BlendFlags 必须为 0DC_RECT/COMPLEX 的源矩形换算裁剪后目标矩形CombinedRect相对OutputRect的位置按比例映射回InputRect保证缩放/平移混合时像素对应正确设备表面兼容经IntEngEnter/Leave用临时位图 DrvCopyBits往返见《分析_25》7.1。2.2 IntEngAlphaBlend — 驱动挂钩分发IntEngAlphaBlend(psoDest,psoSource,pco,pxlo,prclDest,prclSrc,pBlendObj){if(!pco)pcogxcoTrivial;// 无裁剪 → 平凡裁剪if(psurfDest-flagsHOOK_ALPHABLEND)retGDIDEVFUNCS(psoDest).AlphaBlend(...);// 驱动 DrvAlphaBlendif(!ret)retEngAlphaBlend(...);// 软件兜底}调用方[ntgdi/bitblt.c](file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c#L13-L131)NtGdiAlphaBlendAlphaBlendAPI→IntEngAlphaBlend[mouse.c](file:///d:/reactos/win32ss/gdi/eng/mouse.c#L285)alpha 光标的合成《分析_24》3.4AC_SRC_OVER, 255, AC_SRC_ALPHANtGdiEngAlphaBlendUMPD 桩SEH 探测用户RECTL后转发EngAlphaBlend。3. 渐变填充 — gradient.c3.1 EngGradientFill — 模式分发EngGradientFill(psoDest,pco,pxlo,pVertex,nVertex,pMesh,nMesh,prclExtents,pptlDitherOrg,ulMode){switch(ulMode){caseGRADIENT_FILL_RECT_H:/* 矩形水平渐变按行插值 */caseGRADIENT_FILL_RECT_V:/* 矩形垂直渐变按列插值 */for每个 GRADIENT_RECT:IntEngGradientFillRect(...);break;caseGRADIENT_FILL_TRIANGLE:/* 三角形渐变 */for每个 GRADIENT_TRIANGLE:if(IntEngIsNULLTriangle(...))continue;// 跳过退化三角形IntEngGradientFillTriangle(...);break;}}TRIVERTEX提供顶点坐标 16 位 RGBA 颜色pMesh是GRADIENT_RECT2 个顶点索引/GRADIENT_TRIANGLE3 个顶点索引数组。3.2 矩形渐变 — IntEngGradientFillRectBresenham 式颜色插值DDAHVINITCOL/HVSTEPCOL宏用误差累计ec dc; while (ec 0) { c ic; ec - dy; }在两端点颜色间线性插值——避免每像素浮点除法水平渐变逐列 y颜色 c[RGB] 由左→右插值 → DIB_VLine 画整列 垂直渐变逐行 y颜色 c[RGB] 由上→下插值 → DIB_HLine 画整行 裁剪CLIPOBJ_bEnum 枚举矩形 RECTL_bIntersectRect 求交逐块绘制 颜色XLATEOBJ_iXlate(pxlo, RGB(c0,c1,c2))《分析_19》快速路径两端点 RGB 全同单色时跳过插值直接整块DIB_HLine画纯色。3.3 三角形渐变 — IntEngGradientFillTriangle经典扫描线三角形光栅化三个顶点按 y 气泡排序边 DDA三条边各自维护 x/sx/dx/dy/incx/exS_INITLINE/S_DOLINE 等宏 每扫描线 y 边0 (v1→v3) 步进边1 (v1→v2) 步进边2 (v2→v3) 步进 FILLLINE(0,1) / FILLLINE(0,2)在两条边之间从 sx[0] 到 sx[1]/sx[2] 对每个 g颜色由边色 FINITCOL/FDOCOL 再次线性插值水平方向 → DIB_PutPixel(g, sy, Color) 裁剪按 prclExtents 与裁剪矩形求交InY 判定跳过界外行快速路径三顶点 RGB 全同VCMPCLRS为假→ 纯色填充S_FILLLINE直接水平线。3.4 IntEngGradientFill — 驱动挂钩分发HOOK_GRADIENTFILL→DrvGradientFill否则EngGradientFill。调用方[ntgdi/fillshap.c](file:///d:/reactos/win32ss/gdi/ntgdi/fillshap.c#L955-L1091)GreGradientFill/NtGdiGradientFill。4. 与《分析_4》标注对照标注核对《_4》第 47 行alphablend.c 「Alpha 混合」准确。补充只支持AC_SRC_OVER裁剪三档分发NtGdiEngAlphaBlend为 UMPD 桩《_4》第 48 行gradient.c 「渐变填充」准确。补充矩形水平/垂直 三角形两种全部用 Bresenham 式 DDA 颜色插值无浮点含单色快速路径5. 源码索引文件关键内容[alphablend.c](file:///d:/reactos/win32ss/gdi/eng/alphablend.c)EngAlphaBlend校验裁剪分发、IntEngAlphaBlendHOOK 分发、NtGdiEngAlphaBlendUMPD 桩[gradient.c](file:///d:/reactos/win32ss/gdi/eng/gradient.c)EngGradientFill、IntEngGradientFill、IntEngGradientFillRect、IntEngGradientFillTriangle、HV*/S_*/FILLLINE 宏族[ntgdi/bitblt.c](file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c#L13-L131)NtGdiAlphaBlendAlphaBlend API 入口[ntgdi/fillshap.c](file:///d:/reactos/win32ss/gdi/ntgdi/fillshap.c#L955-L1091)GreGradientFill/NtGdiGradientFillGradientFill API 入口[dib/dib.h](file:///d:/reactos/win32ss/gdi/dib/dib.h#L42-L55)PFN_DIB_AlphaBlend、DIB 函数表[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h)BLENDOBJ/AC_SRC_、TRIVERTEX/GRADIENT_定义关联模块设备表面桥梁IntEngEnter/IntEngLeave《分析_25》7.1颜色转换XLATEOBJ_iXlate《分析_19》裁剪枚举CLIPOBJ_bEnum/CLIPOBJ_cEnumStart《分析_4》3.2消费方alpha 光标《分析_24》3.4、pandisp 包装《分析_25》PanAlphaBlend/PanGradientFill6. 各函数作用和使用说明6.1 alphablend.c6.1.1 EngAlphaBlend — Alpha 混合软件实现核心win32k 导出BOOLEngAlphaBlend(SURFOBJ*psoDest,SURFOBJ*psoSource,CLIPOBJ*ClipRegion,XLATEOBJ*ColorTranslation,RECTL*DestRect,RECTL*SourceRect,BLENDOBJ*BlendObj);参数说明psoDest/psoSource目标/源表面可为设备表面内部经 IntEngEnter 换临时位图ClipRegion裁剪区域NULL 无裁剪ColorTranslation颜色转换对象可 NULLDestRect/SourceRect目标/源矩形可重叠校验BlendObj混合参数BlendOp/BlendFlags/SourceConstantAlpha/AlphaFormat使用要点只支持AC_SRC_OVERBlendFlags必须为 0AlphaFormat仅可含AC_SRC_ALPHA——不满足直接返回 FALSE。源矩形必须完整落在源表面内否则ERROR_INVALID_PARAMETER。psoDest psoSource且矩形重叠时返回 FALSE防自混合。内部自动处理裁剪三档TRIVIAL/RECT/COMPLEX与设备表面回退返回 FALSE 表示失败TRUE 表示已绘制含裁剪为空的空操作。调用方NtGdiEngAlphaBlend、IntEngAlphaBlend的软件兜底路径、鼠标 alpha 光标[mouse.c](file:///d:/reactos/win32ss/gdi/eng/mouse.c#L285)。6.1.2 IntEngAlphaBlend — 驱动挂钩分发内部BOOLIntEngAlphaBlend(SURFOBJ*psoDest,SURFOBJ*psoSource,CLIPOBJ*pco,XLATEOBJ*pxlo,RECTL*prclDest,RECTL*prclSrc,BLENDOBJ*pBlendObj);使用要点引擎内部首选入口目标表面挂钩HOOK_ALPHABLEND→ 调驱动DrvAlphaBlend返回 FALSE 或未挂钩 →EngAlphaBlend软件兜底。pco NULL时自动用全局平凡裁剪gxcoTrivial。空裁剪rclBounds 退化直接返回 TRUE。调用方[ntgdi/bitblt.c](file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c#L131)NtGdiAlphaBlend。6.1.3 NtGdiEngAlphaBlend — UMPD 系统调用桩BOOLNtGdiEngAlphaBlend(SURFOBJ*psoDest,SURFOBJ*psoSource,CLIPOBJ*ClipRegion,XLATEOBJ*ColorTranslation,PRECTL upDestRect,PRECTL upSourceRect,BLENDOBJ*BlendObj);使用要点UMPD用户模式打印驱动经 gdi32 → win32u 调用进入内核的入口。用ProbeForRead SEH 把用户RECTL拷入内核栈再转发EngAlphaBlend用户指针探测。仅供 UMPD 路径使用内核驱动直接用EngAlphaBlend。6.2 gradient.c6.2.1 EngGradientFill — 渐变填充分发软件实现win32k 导出BOOLEngGradientFill(SURFOBJ*psoDest,CLIPOBJ*pco,XLATEOBJ*pxlo,TRIVERTEX*pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,RECTL*prclExtents,POINTL*pptlDitherOrg,ULONG ulMode);参数说明pVertex/nVertex顶点数组坐标 16 位 RGBA及数量pMesh/nMesh网格数组GRADIENT_RECT2 索引或GRADIENT_TRIANGLE3 索引及数量prclExtents整个网格的包围矩形pptlDitherOrg抖动原点渲染坐标偏移ulModeGRADIENT_FILL_RECT_H/GRADIENT_FILL_RECT_V/GRADIENT_FILL_TRIANGLE使用要点pco NULL时用全局平凡裁剪。按ulMode分发矩形模式逐GRADIENT_RECT调IntEngGradientFillRect三角形模式逐GRADIENT_TRIANGLE调IntEngGradientFillTriangle退化三角形自动跳过。任一子填充失败则中断循环break但整体仍返回 TRUE半成功语义。未识别的ulMode不进入任何分支返回 FALSE。6.2.2 IntEngGradientFill — 驱动挂钩分发内部BOOLIntEngGradientFill(SURFOBJ*psoDest,CLIPOBJ*pco,XLATEOBJ*pxlo,...);使用要点目标表面挂钩HOOK_GRADIENTFILL→DrvGradientFill否则EngGradientFill。调用方[ntgdi/fillshap.c](file:///d:/reactos/win32ss/gdi/ntgdi/fillshap.c#L1071)GreGradientFill/NtGdiGradientFill。6.2.3 IntEngGradientFillRect — 矩形渐变填充内部BOOLIntEngGradientFillRect(SURFOBJ*psoDest,CLIPOBJ*pco,XLATEOBJ*pxlo,TRIVERTEX*pVertex,ULONG nVertex,PGRADIENT_RECT gRect,RECTL*prclExtents,POINTL*pptlDitherOrg,BOOL Horizontal);使用要点仅被EngGradientFill矩形模式调用HorizontalTRUE水平渐变逐列DIB_VLineFALSE 垂直逐行DIB_HLine。颜色用 Bresenham DDAHVINITCOL/HVSTEPCOL在两端点间插值经XLATEOBJ_iXlate转目标色。端点同色单色矩形走快速路径整块DIB_HLine。内部IntEngEnter/Leave处理设备表面无需调用方关心。6.2.4 IntEngGradientFillTriangle — 三角形渐变填充内部BOOLIntEngGradientFillTriangle(SURFOBJ*psoDest,CLIPOBJ*pco,XLATEOBJ*pxlo,TRIVERTEX*pVertex,ULONG nVertex,PGRADIENT_TRIANGLE gTriangle,RECTL*prclExtents,POINTL*pptlDitherOrg);使用要点仅被EngGradientFill三角形模式调用内部对三个顶点按 y 排序气泡排序。三边 DDA 步进 扫描线在两边间做水平颜色再插值FILLLINE/FINITCOL/FDOCOL逐像素DIB_PutPixel。三顶点同色VCMPCLRS为假走纯色快速路径。裁剪按prclExtents与枚举矩形求交InY跳过界外扫描线。6.2.5 IntEngIsNULLTriangle — 退化三角形检测内部静态staticBOOLIntEngIsNULLTriangle(TRIVERTEX*pVertex,GRADIENT_TRIANGLE*gt);使用要点任意两顶点坐标相同 → 返回 TRUE面积为零EngGradientFill据此跳过该三角形。内部辅助函数外部不可见。本文档基于 ReactOS 源代码win32ss/gdi/eng/alphablend.c、gradient.c及关联模块分析2026 年 8 月
返回列表