
目录前言结论验证目标测试平台/场景/评定平台测试场景评定方式测试 1分离进程、共享内存、全分辨率实现参数看到了什么测试 2分离进程、共享内存、缩略图实现参数看到了什么测试 3分离进程、DXGI 共享纹理、全分辨率实现参数看到了什么以上共同问题冻帧测试 4同进程、全分辨率实现参数看到了什么外壳差异不同外壳表现20 窗区分度明显WinUI3数据上最好领先幅度小WinForms紧随其后最轻量WPF与 WinForms 同档轻画面稍松Avalonia多窗口时稳定地落后一档网页 · 读回贴图少窗可以多窗减半网页 · 页内 WebGL随窗口数线性崩溃主观观察原理为什么跨进程会冻帧而同进程帧率低也顺如何保证对比公平画面清晰度局限与读数提示结论建议核心结论同进程外壳的选择跨进程仍然适用的场景前言在核显模式下同一份 GPU 画面如何稳定流畅地送进几十个窗口从“渲染与显示分进程”出发经过共享内存、缩略图、GPU 共享纹理三轮改进最终在“同进程直接上屏”上得到质的提升再在同进程模式下横向比较WinForms、WPF、WinUI3、Avalonia 与两种网页方案。分别给出了实现参数和实测数据。测试平台Windows 11 · 2560×1600 240Hz ·Intel UHD核显渲染核心.NET 8 · Vortice 3.8.3 · Direct3D 11 Direct2D构建显示器笔记本接入到核显的内屏默认屏。压力星云场景1920×1080 画布约 12.6 万个图元不限垂直同步。结论窗口少时四种架构差别不大1–4 个窗口下四组的显示帧率在同一级差异在整机热降频造成的波动约 ±25%之内。窗口一多跨进程三组全部掉队20 个窗口、重画面下跨进程三组平均只有 27–30 fps最差 10% 时刻跌到 8–19 fps肉眼可见地“冻帧”同进程原生外壳为 47–59 fps最差 10% 为 45–59 fps。轻画面 20 窗跨进程 47–68 fps同进程 184–239 fps。同进程的优势不只是“更快”而是“更稳”它的最差时刻帧率和平均帧率几乎重合——帧率低时是“慢但匀”不会忽快忽停。同进程下原生外壳之间没有本质差异仅有细微差别网页方案在多窗口下只剩一半甚至更低页内 WebGL 自绘随窗口数线性崩溃。验证目标场景很简单一个渲染核心在 GPU 上实时绘制画面这份画面需要同时出现在多个显示容器里——操作台上的预览、独立的显示窗口、扩展屏上的全屏窗口。容器的数量少则几个多则几十个。我们要找一种稳定、高效、流畅的方式让同一份 GPU 输出在显示容器数量较多、画面压力较大的情况下依然完整、流畅、稳定地呈现。理想状态是呈现环节基本不用考虑数量和压力的限制。核心指标含义预期流畅每个窗口实际换上新画面的频率越接近渲染帧率越好20–30 个窗口依然流畅稳定帧与帧的间隔是否均匀平均帧率高但时快时停看起来就是“冻帧”开到 50–100 个窗口不崩溃至少带得动围绕这个目标我们先后尝试了两大思路、四组方案。前三组都是“渲染进程 显示进程”的跨进程架构第四组把渲染和显示放进同一个进程。下面按尝试的先后顺序展开。测试平台/场景/评定平台硬件笔记本 · Intel UHD 核显驱动显示 · 屏幕 2560×1600 240Hz · 系统缩放 150%渲染核心.NET 8 Vortice 3.8.3C# 对 DirectX 的薄封装Direct3D 11 设备 Direct2D 绘制DXGI 交换链上屏构建全部 Release 构建Debug 下 JIT 会让 C# 绘制慢 20–25%不可用于对比节拍渲染端统一封顶到屏幕刷新率 240 fps高精度可等待计时器 短自旋显示端按垂直消隐取帧显示尺寸每个显示窗口的画面区为 960×540画布的一半各外壳统一按物理像素 1:1 对齐测试场景场景画布内容与压力来源用途压力星云重1920×1080约 12.6 万个图元旋臂星系、银河带、星云纤维、频谱山脉六万余粒子按图层合批成 Direct2D 精灵批次叠加混合再过一道全屏泛光。大面积柔光压填充率逐帧重建路径几何压 CPU海量精灵压顶点吞吐看压力下的帧率与稳定性扫描时钟轻1920×120大号数字时钟精确到 1/100 秒 横向扫光绘制量很小小尺寸在以下任何方式都有不错的表现轻松超过60fps甚至很多在200fps以上以下将不作为测试重点渲染几乎不是瓶颈专门看“通路”本身能否跟上 240Hz以及帧是否连续两个测试场景总览评定方式指标定义显示帧率平均每 200 ms 统计一次每个窗口实际换上新画面的次数换算成 fps所有窗口、所有样本取平均。上限为刷新率 240。注意它不是渲染端出帧数。最差 10%p10所有样本从低到高排序第 10% 位置的帧率。越接近平均值越平稳远低于平均值说明有一段时间几乎不出新帧也就是肉眼看到的冻帧、顿挫。卡顿占比连续 0.5 秒以上没有新帧的样本比例。额外延迟仅跨进程组渲染端写完一帧到显示端取到并开始上屏的时间取 p50 / p90。同进程组渲染完立即在同一循环里上屏没有这一跳。每个用例先预热 4 秒再采样 10 秒用例之间冷却 5 秒。核显笔记本会热降频同一配置前后两次能差 20% 以上所以本文把 20% 以内的差距视为同级别只有超出这个范围或趋势一致的差异才下结论。测试 1分离进程、共享内存、全分辨率第一个思路很自然把渲染进程和显示进程分开。好处有三点渲染进程只管画不受任何界面卡顿的影响显示端可以随意更换形式——WinForms、WPF、WinUI3 都能订阅同一份画面某个显示窗口崩溃不会拖垮渲染。两个进程之间传画面最直接的办法是共享内存渲染端把 GPU 画面读回到 CPU写进一块命名的内存映射文件MMF显示端从里面取出来再上传给自己的 GPU 显示。橙色为 CPU 侧、蓝色为 GPU 侧的工作。像素在 GPU → CPU → GPU 之间往返一次且显示窗口越多CPU 侧拷贝越多。实现参数环节做法读回3 个 staging 纹理轮转用MapFlags.DoNotWait探测是否已完成只有环满才阻塞避免每帧 CPU 等 GPU 跑完整个队列共享内存3 槽每槽带序号写入时为奇数、写完为偶数读完校验序号未变IsIntact被覆盖的半帧直接丢弃不显示撕裂画面传输量1920×1080×4 字节 ≈8.3 MB / 帧 / 窗口60 fps × 10 窗 ≈ 5 GB/s 的内存拷贝显示端WinForms先Map(WriteDiscard)动态纹理再取槽、一次 memcpy、校验后由 GPU 缩放 PresentWPFWriteableBitmap.Lock后直接拷进后台缓冲WinUI3取原生缓冲指针直接拷显示节拍WinForms 等垂直消隐IDXGIOutput.WaitForVBlankWPF / WinUI3 跟随各自的合成节拍看到了什么只开 1 个显示窗口时显示帧率能跟上渲染端但离“丝滑”还有距离重画面 86 fps且多了约 31 ms 延迟。开到 10 个、20 个窗口帧率掉到 30 fps 左右而且最差时刻只有个位数。组 1 · WinForms 显示端1 窗4 窗10 窗20 窗重画面 · 平均 fps86.258.630.930.0重画面 · 最差 10%55.052.99.68.2重画面 · 额外延迟 p5031 ms38 ms37 ms37 ms轻画面 · 平均 fps197.9196.5208.157.7轻画面 · 最差 10%154.2162.3181.312.1数据artifacts/bench/20261005-104639、-104951、-105308、-105642窗口数扫描同一时段连续测得。轻画面在 10 窗时还撑得住画布只有 1920×120每帧不到 1 MB到 20 窗也崩了重画面每帧 8.3 MB从 10 窗起就明显吃不消。瓶颈在“每个窗口各搬一份完整画面”数据量随窗口数线性增长读回与拷贝都压在 CPU 和内存带宽上。测试1 - 随机采样 - winform , 1 窗测试1 - 随机采样 - winform , 10 窗测试1 - 随机采样 - winform , 50 窗测试 2分离进程、共享内存、缩略图渲染本身的帧率先放一边第一个改善方向是让显示帧率尽可能接近渲染帧率。既然瓶颈是数据量那就少搬一点渲染端在 GPU 上先把画面缩到显示窗口的实际尺寸960×540再读回数据量降到 1/4显示端只取最新的一帧来不及取的旧帧直接跳过不排队。实现参数环节做法缩略尺寸按显示端上报的实际预览尺寸生成无尺寸时退到画布一半受槽容量限制不是固定的小图传输量960×540×4 字节 ≈2.1 MB / 帧为组 1 的 1/4其余读回环、三槽共享内存、撕裂校验、显示端上屏方式与组 1 相同看到了什么组 2 · WinForms 显示端1 窗4 窗10 窗20 窗重画面 · 平均 fps54.795.223.427.2重画面 · 最差 10%47.158.87.318.9轻画面 · 平均 fps195.5192.482.047.3轻画面 · 最差 10%149.9168.718.52.5轻画面 · 卡顿占比0%0%0%9.5%少量窗口时确实有改善4 窗重画面 95 fps是这一组的最好成绩但到 10 窗以上和组 1 一样崩溃20 窗轻画面甚至出现 9.5% 的样本超过半秒没有新帧。这是一种“有损”的改善缩略图按当前预览尺寸生成在窗口大小不变时肉眼差别不大但窗口一放大、或要全屏显示就只能拉伸低分辨率画面。它是用分辨率换带宽而且没有改变“GPU → CPU → GPU”的往返本质提升有限。测试2 - 随机采样 - 1/4缩放winform1 窗测试2 - 随机采样 - 1/4缩放winform10 窗测试2 - 随机采样 - 1/4缩放winform50 窗测试 3分离进程、DXGI 共享纹理、全分辨率组 1、组 2 的根本问题是把 GPU 画面拷贝到共享的 CPU 内存再推回显示端的 GPU。既然渲染端和显示端在同一块显卡上为什么不直接共享 GPU 上的纹理这就是组 3DXGI 共享纹理。全程在 GPU 内完成CPU 只传递“哪一块纹理可读”的信号。实现参数环节做法共享资源3 块 1920×1080 共享纹理DXGI 共享句柄每块带一个KeyedMutex做跨进程互斥写端以 0 ms 超时尝试加锁只写尚未发布的槽从不等待读端读端以 2 ms 超时抢锁 →CopyResource到本进程纹理 → 立即放锁 → 再 Present持锁时间只有一次 GPU 拷贝避免多个读端互相阻塞安全检查校验显卡 LUID确保两端在同一块 GPU 上CPU 像素拷贝0看到了什么组 3 · WinForms 显示端1 窗4 窗10 窗20 窗重画面 · 平均 fps106.161.623.929.5重画面 · 最差 10%65.857.77.613.1重画面 · 额外延迟 p503.0 ms4.3 ms4.2 ms29.7 ms轻画面 · 平均 fps193.6190.563.667.6轻画面 · 最差 10%156.9156.729.534.1轻画面 · 额外延迟 p503.0 ms2.3 ms2.8 ms3.4 ms相比组 1组 3 有了较大的提升额外延迟从 30–40 ms 降到 2–4 ms1 个窗口时重画面达到 106 fps。单窗口时渲染和显示分在两个进程可以在 CPU 与 GPU 上交错执行跨进程并不吃亏。不过单窗口成绩受机器状态影响很大同进程单窗在另一时段测到 94–108 fps这里不据此排名。但窗口一多结果与组 1、组 2 几乎重合10 窗重画面 24 fps、最差时刻 7.6 fps。数据通道已经不是瓶颈了帧率却依然上不去、依然冻帧——问题出在别处。测试3 - 随机采样 - winform, 1 窗测试3 - 随机采样 - winform, 10 窗测试3 - 随机采样 - winform, 50 窗以上共同问题冻帧三组跨进程方案的共同问题冻帧回到最初的预期随便开二三十个窗口都要流畅开到 50 或 100 个不能崩溃。三组跨进程方案都没有达到。更重要的是它们共享一个肉眼很容易察觉的现象——冻帧画面会停住一下再跳到后面即使平均帧率不算太低。数据上冻帧表现为“最差 10%”远低于平均值。20 窗轻画面下组 2 平均 47 fps最差 10% 只有 2.5 fps组 3 平均 68 fps最差 10% 只有 34 fps。测试 4同进程、全分辨率继续分析瓶颈测试 3 已经把数据量降为零拷贝剩下的限制来自跨进程这件事本身——两个进程各有自己的节拍、自己的 D3D 设备需要跨进程加锁同步GPU 还要在多个进程之间分时调度。那就把渲染和显示放进同一个进程。一个设备、一条命令队列、一个循环画一帧立刻交给所有窗口再画下一帧。没有读回、没有跨进程锁、没有第二个时钟。实现参数环节做法设备与线程整个进程只有一个 D3D11 设备渲染与上屏在专用渲染线程上完成每个窗口一个子 HWND 一条 DXGI 交换链FlipDiscard2 个缓冲后台缓冲按窗口物理像素创建上屏同一张画布位图对每个窗口执行一次 Direct2DDrawBitmap缩放 Present缩放比接近整数时按整数比例绘制避免整幅重采样界面线程只处理窗口消息与 HUD200 ms 刷新一次不参与每帧绘制各外壳只负责提供一个子 HWND节拍渲染循环用高精度可等待计时器封顶到刷新率 240看到了什么这一次是本质的提升。同样用 WinForms 外壳同样的四个窗口档位组 4 · 同进程 WinForms1 窗4 窗10 窗20 窗重画面 · 平均 fps63.948.763.953.8重画面 · 最差 10%56.543.563.151.1轻画面 · 平均 fps199.2185.5171.9177.4轻画面 · 最差 10%168.5138.0145.3169.5两个特征非常明显帧率随窗口数平缓变化没有断崖。这一轮扫描中重画面从 1 窗到 20 窗都在 49–64 fps 之间这个区间就是热降频波动的幅度轻画面在 172–199 fps 之间。另一时段的补测里单窗可达 94–108 fps10 窗 63–64、20 窗 57–59 fps每多一个窗口就多一次缩放绘制和 Present成本线性增加、可以预测不会像跨进程那样在 10 窗附近突然崩溃。最差时刻紧贴平均值。10 窗重画面平均 63.9、最差 10% 63.120 窗轻画面平均 177.4、最差 10% 169.5。帧率即使不高也是均匀的——这正是肉眼看不到冻帧的原因。四组放在一起四张图的数据来自同一时段连续完成的窗口数扫描每组都用 WinForms 作为显示端或外壳。1–4 窗时线条交错是热降频波动造成的不代表排名10 窗以后的分叉才是架构差异。外壳差异确定了同进程方向之后下一个问题是用哪种界面框架做外壳。我们用同一个渲染核心分别接入六种外壳外壳接入方式上屏路径WinFormsPanel 本身就是 HWND渲染线程直接对子窗口交换链 PresentWPFHwndHost托管子 HWND同上画面区按物理像素 1:1 对齐WinUI3在窗口内创建子 HWND同上AvaloniaNativeControlHost托管子 HWND同上网页 · 读回贴图WebView2每个窗口一个页面C# 渲染一次 → 读回 →SharedBuffer一次投递给所有页面 → 页面用 WebGLtexSubImage2D贴图上屏网页 · 页内 WebGLWebView2每个页面自己画每个页面用 WebGL 独立绘制同一场景由浏览器合成上屏前四种原生外壳最终都把同一份画面交给 DXGI 交换链差异只来自窗口框架本身的开销消息循环、自身合成器、HUD 更新等。网页·读回贴图仍然只渲染一次但上屏交给浏览器进程完成网页·页内 WebGL 则是每个窗口各渲染一次比较的是“浏览器作为渲染器”不是同一种架构单列作参照。不同外壳表现为抵消运行顺序与发热的影响10 窗分别按正序WinForms 先跑且排在 9 个跨进程用例之后和倒序网页先跑只跑同进程各测一轮4 窗为两轮平均。每格为“平均 / 最差 10%”单位 fps。重画面1 窗4 窗10 窗 · 正序10 窗 · 倒序20 窗WinForms93.6 / 85.656.9 / 54.049.4 / 48.362.6 / 61.457.0 / 56.2WPF106.9 / 102.760.0 / 55.350.9 / 48.864.1 / 61.855.3 / 53.1WinUI3107.2 / 102.657.7 / 52.128.4 / 21.864.5 / 63.759.4 / 58.5Avalonia107.8 / 104.055.5 / 52.131.0 / 26.163.8 / 62.846.7 / 45.0网页 · 读回贴图102.0 / 97.261.8 / 56.334.2 / 31.257.3 / 54.726.4 / 25.7网页 · 页内 WebGL96.3 / 90.030.8 / 29.410.4 / 9.915.9 / 15.87.4 / 7.4轻画面上限 2401 窗4 窗10 窗 · 正序10 窗 · 倒序20 窗WinForms239.8 / 239.5239.9 / 239.7237.3 / 236.1239.7 / 239.7233.4 / 227.9WPF239.7 / 239.6239.9 / 239.7236.4 / 227.6238.0 / 232.2223.8 / 209.2WinUI3239.8 / 239.7239.9 / 239.6239.8 / 239.5239.9 / 239.5239.4 / 238.4Avalonia239.6 / 239.7239.9 / 239.6224.7 / 217.0231.8 / 227.2183.8 / 172.2网页 · 读回贴图238.1 / 236.0226.0 / 206.5239.1 / 237.8229.1 / 190.0119.2 / 113.3网页 · 页内 WebGL240.0 / 240.0180.0 / 180.0192.0 / 192.0240.0 / 240.0107.6 / 103.2数据1 窗 20261005-1114214 窗 20261005-071534 与 -072917 平均10 窗正序 20261005-110042倒序 -11192520 窗 -112430。20 窗区分度明显1–10 窗下原生外壳之间的差距都在波动范围内到 20 窗才稳定拉开20 窗重画面平均 fps轻画面平均 fpsWinUI359.4239.4WinForms57.0233.4WPF55.3223.8Avalonia46.7183.8网页 · 读回贴图26.4119.2网页 · 页内 WebGL7.4107.6重画面条长以 70 fps 为满格轻画面以 240 fps 为满格。WinUI3数据上最好领先幅度小轻画面在所有档位都保持 ≥239.4 fps最差 10% 也几乎贴着上限是六种外壳中唯一做到的20 窗重画面 59.4 fps 同样第一。但它比 WinForms 只高 4%重和 3%轻优势有限。10 窗正序时的 28.4 fps 在倒序中没有复现64.5 fps判断为当时机器的发热状态所致不计入排名。测试4 -随机采样 - winui3 - 1 窗:测试4 -随机采样 - winui3 - 10 窗测试4 -随机采样 - winui3 - 50 窗WinForms紧随其后最轻量20 窗 57.0 / 233.4 fps最差 10% 紧贴平均值结构最简单Panel 本身就是 HWND没有额外的合成层也不存在高 DPI 下的像素对齐问题。测试4 -随机采样 - winform-1 窗:测试4 -随机采样 - winform-10 窗测试4 -随机采样 - winform-50 窗WPF与 WinForms 同档轻画面稍松重画面与 WinForms 几乎相同55.3 vs 57.0轻画面在 10 窗、20 窗时最差 10% 降到 209–232 fps帧间隔比前两者略松。需要注意像素对齐否则画面发虚。测试4 -随机采样 - wpf - 1 窗:测试4 -随机采样 - wpf-10 窗测试4 -随机采样 - wpf - 50 窗Avalonia多窗口时稳定地落后一档1–4 窗与其他外壳无差别从 10 窗开始轻画面在两轮里都是原生外壳中最低224.7、231.8 fps20 窗时重画面比 WinUI3 低 21%轻画面低 23%。可能与 Avalonia 自身的合成器在每个窗口里持续运行有关本文没有进一步剖析。测试4 -随机采样 - Avalonia - 1窗:测试4 -随机采样 - Avalonia - 10 窗:测试4 - 随机采样 - Avalonia - 50 窗:网页 · 读回贴图少窗可以多窗减半4 窗重画面 61.8 fps甚至略高于原生外壳——上屏工作被转移到浏览器进程与渲染并行。但轻画面 4 窗时最差 10% 已降到 206 fps到 20 窗重画面 26.4、轻画面 119.2 fps约为原生外壳的一半。效果太差不需要采样该方式属于完全不考虑的方案。网页 · 页内 WebGL随窗口数线性崩溃单窗口 96 fps 时与其他方式看不出差别4 窗 31、10 窗 10–16、20 窗 7.4 fps。每个页面都要自己渲染一遍完整场景算力随窗口数线性增长浏览器还会自行调度帧率多窗时出现固定的 180、192 fps。追求多窗口高性能时它不是有效选择。测试4 - 随机采样 - WebGL- 1 窗测试4 - 随机采样 - WebGL- 10 窗测试4 - 随机采样 - WebGL- 50 窗主观观察批量启动 50 个窗口肉眼看到的现象描述如下外壳肉眼观察WinForms流畅、稳定、清晰、启动后画面显示快速。页面局部会有闪烁现象。WPF流畅差于winform、稳定、清晰、启动后画面显示稍慢。一开始画面模糊后来进行了修复。WinUI3流畅优于winform、清晰、启动后画面显示快速与winform类似。调试时出现过初始画面异常主观感觉稳定性欠佳。Avalonia流畅明显差于以上3个、稳定、清晰、启动后画面显示快速。网页极其卡顿仅一两帧清晰启动后画面延迟5秒左右才显示。与以上原生的框架相差一个明显的等级。原理为什么跨进程会冻帧而同进程帧率低也顺组 3 已经做到零 CPU 拷贝、2–4 ms 延迟为什么多窗口下仍然冻帧根本原因是跨进程时出帧和上屏由两个互不同步的时钟驱动中间隔着一个“只取最新帧”的交接点导致每一帧在屏幕上停留的时间忽长忽短。跨进程渲染端约 50 fps 且间隔有抖动显示端每次刷新取“最新一帧”60Hz 示意竖线为刷新时刻渲染端出帧ABCDEFGH屏幕显示ABCC 重复DFF 重复G结果E 还没来得及显示就被 F 覆盖跳帧C、F 各停留两次刷新冻帧。帧率不算低每帧停留的刷新次数却是 1-1-2-1-2-1……同进程画一帧 → 立即交给所有窗口 → 再画下一帧每帧恰好显示一次。30 fps 就是稳定地每隔固定几次刷新换一帧像电影的 24 帧一样“慢但匀”。在这个“节拍不同步”的基础上跨进程还有几个放大因素因素跨进程时发生了什么同进程交接点丢帧组 1/2显示端拷贝时渲染端正在写同一槽校验失败只能丢弃屏幕沿用上一帧。组 3渲染端持锁写纹理时读端拿不到锁这一拍沿用旧画面同一线程先画后交不存在“撞车”GPU 跨进程分时渲染进程与 N 个显示进程各有 D3D 设备GPU 调度器在它们之间切换重画面时渲染进程的大批命令可能把显示进程的拷贝和上屏挤过垂直同步错过一次刷新就多冻一拍一个设备、一条队列顺序天然确定CPU 调度N 个显示进程互相抢 CPU后台窗口的进程调度优先级更低线程唤醒晚于预期就会错过刷新一个渲染线程按计时器推进合成器截止时间每个显示进程各自把画面交给桌面合成器谁晚到一点就等下一次刷新晚到的时机是随机的所有窗口在同一循环里连续提交时机一致动画时间与显示时间错位画面内容按渲染时刻计算但显示时刻不固定运动看起来一顿一顿渲染到显示的延迟基本恒定如何保证对比公平对比实验最怕的是比出来的不是架构差异而是“某一组写得不好”。因此在出最终数据之前我们对每一组的实现逐项核对确保每一组都用它所属架构里最快的正确做法。下列问题都曾真实影响过数据均已修正发现的问题对结果的影响修正显示端节拍用DwmFlushGPU 被多个进程占满时一次等待可达几百毫秒WinForms 跨进程端被严重低估组 3 · 10 窗 14 fps改为WaitForVBlank同样按刷新率但不受 GPU 负载影响→ 39 fpsWinForms 显示端用 GDI HALFTONE 在 CPU 上缩放半尺寸预览只有 12.6 fps改为动态纹理上传 GPU 缩放上屏跨进程渲染端不限速轻画面下空跑 1000–5000 fps多出的帧屏幕显示不了却在抢显示端的 CPU/GPU等于专门惩罚跨进程组渲染端与同进程引擎统一封顶到 240 fps同步读回、双重拷贝CPU 每帧等 GPU 跑完整个队列渲染帧率被拖低约 35%3 深读回环 非阻塞探测单次 memcpy 直写共享内存共享纹理无同步 / 持锁上屏无同步时读到半帧却“白占便宜”持锁 Present 时多读端互相阻塞KeyedMutex 同步持锁只做一次 GPU 拷贝WPF 组 3 由 WPF 渲染节拍驱动上屏可视树静止时 WPF 节拍降到 60Hz 以下轻画面只有 53 fps改为独立线程按垂直消隐上屏→ 239 fps同进程显示帧率未封顶出现 400 fps240Hz 屏根本显示不了统一记录min(fps, 刷新率)统计窗口没有截止采样结束后关闭窗口期间的“卡顿”被计入卡顿占比虚高到 20–50%只统计采样区间内的样本网页外壳统计的是 C# 出帧没有反映网页实际上屏改为记录各页面实际上屏帧率除 WinForms 外的外壳画面发虚窗口尺寸按设备无关单位估算差一两像素就整幅重采样肉眼看起来不清晰画面区按物理像素 1:1 对齐同时段 A/B 实测确认对帧率无影响画面清晰度在 150% 系统缩放下WPF 等框架以设备无关单位布局1 个单位 1.5 个物理像素。原实现按“画面尺寸 估算边框”反推窗口大小画面区实际是 962 像素宽而不是 960于是整幅画面被放大 1.002 倍——每个像素都和邻居混合星点和小字发糊。修正后画面区按物理像素精确定尺寸、位图 DPI 等于屏幕 DPI、文字按像素格排版WPF 的清晰度指标从 13.5 升到 21.4与 WinForms21.7持平。我们用环境变量开关在同一时段交替运行新旧两种做法帧率差异有正有负且均在波动范围内确认清晰化不影响帧率。修正前星点晕开4 倍最近邻放大修正后与 WinForms 一样锐利局限与读数提示单台核显笔记本绝对数值只代表这台机器独立显卡上所有方案都会更高但架构之间的相对关系与多窗口下的分叉趋势是可复现的。热降频同一配置前后两次可差 20%–25%不同时段之间差得更多同进程 WinForms 单窗在两个时段分别为 64 与 94 fps。因此本文只在同一轮测试内做横向比较1–4 窗的小差异不作结论窗口数扫描在同一时段连续完成。采样粒度 200 ms单帧级的顿挫看不到“最差 10%”是冻帧的近似度量。运行顺序同一场景内同进程用例排在跨进程用例之后运行机器温度更高对同进程组是不利条件结论偏保守。同进程外壳之间的比较另做了倒序复测正序中 WinUI3、Avalonia 的 10 窗低值28–31 fps在倒序中没有复现64 fps。网页外壳额外启动浏览器渲染进程和 GPU 进程属于架构自带成本计入结果。结论建议核心结论追求本地多窗口预览的极致性能时应当选择同进程直接上屏。这是在当前压力测试下得出的初步结论依据如下20 窗跨进程组 1 / 2 / 3同进程四种原生外壳重画面 · 平均30.0 / 27.2 / 29.5 fps46.7 – 59.4 fps重画面 · 最差 10%8.2 / 18.9 / 13.1 fps45.0 – 58.5 fps轻画面 · 平均57.7 / 47.3 / 67.6 fps183.8 – 239.4 fps轻画面 · 最差 10%12.1 / 2.5 / 34.1 fps172.2 – 238.4 fps肉眼观感冻帧、跳帧帧率低时也均匀跨进程架构的上限不在于数据怎么传组 3 已经做到零拷贝、2–4 ms 延迟而在于两个进程、两个时钟、跨进程锁和 GPU 分时这些结构性成本。同进程把这些成本全部去掉一个设备、一个循环每帧恰好交给每个窗口一次。同进程外壳的选择按 20 窗数据仅从性能表现排序为WinUI3可能不稳≥ WinForms算稳≥ WPF稳 Avalonia稳≫ 网页·页内 WebGL绝不考虑。前三者的差距在 4%–7% 之间属于“细微但在多窗下可复现”的差异1–10 窗时差距落在波动范围内可视为同档。Avalonia 在 20 窗时落后约 20%少量窗口时没有差别。网页方案在多窗口下都明显落后页内 WebGL 随窗口数线性崩溃。因此在原生外壳之间性能不应成为唯一依据同样要考虑框架成熟度和稳定性WinUI3 数据最好但需要 Windows App SDK 运行时调试中出现过初始画面异常稳定性不足WinForms 最轻量、最省心但是做应用时样式太传统WPF 生态成熟但要处理好高 DPI 下的像素对齐Avalonia 可以跨平台代价是高压力多窗口时的略微偏差的性能。从某种角度来说Avalonia 具有稳且全能的趋向。从稳定性上来看WinForms 、WPF 、 Avalonia 三者可以任选其一不具有量级差异。跨进程仍然适用的场景当显示端需要与渲染进程隔离独立崩溃域、第三方显示程序、权限隔离且窗口数不超过3、4个时跨进程依然可用。这种情况下优先选组 3DXGI 共享纹理零 CPU 拷贝额外延迟只有 2–4 ms远低于前两个测试组的 20–40 ms。以上验证的最强性能的UI框架是WinUI3,下面是它在同进程开启 100 个窗口时的表现求稳推荐WinForms、WPF、Avalonia求快推荐WinUI3 、WinForms、WPF。注意以上的图示效果属于随机采样帧率是实时计算的会上下跳动。文中的统计相关的数字都是使用的稳定平均值因此如果图示于数据有略微差异以数据统计为准。