4、帧率基准测试:在相同硬件上运行官方Demo,测量FPS
帧率,说白了就是GUI的“心跳”。你界面再好看,一卡顿,用户立马就烦了。我这些年做嵌入式GUI,最怕的就是产品经理跑过来说:“这个滑动效果能不能再丝滑一点?”——嗯,丝滑的背后,就是帧率。
这一章,咱们不扯虚的。直接在同一个硬件上,跑TouchGFX和LVGL的官方Demo,用数据说话。看看这两个框架,到底谁更能榨干硬件的性能。
4.1 为什么帧率是硬指标?
帧率(FPS,Frames Per Second)就是每秒画面刷新的次数。60 FPS意味着每16.6ms就要画完一帧。人眼对30 FPS以上就感觉流畅了,但触摸交互这种场景,低于45 FPS就会有明显的“拖影感”。
我在一个医疗设备项目里遇到过,客户非要在低端Cortex-M4上跑复杂图表。当时LVGL的帧率掉到18 FPS,触摸笔迹断断续续。后来换了TouchGFX的局部刷新策略,勉强拉到32 FPS——虽然还是不够,但至少能用了。你看,帧率这东西,直接决定了你的产品能不能交付。
4.2 测试环境:一碗水端平
既然是“相同硬件”,那就得把条件锁死。我选了一块STM32F429I-DISCO开发板,主频180MHz,带一块2.4寸320x240的LCD,使用LTDC接口。内存方面,外部SDRAM 8MB,内部SRAM 256KB。
两个框架都使用相同的底层驱动:
- LCD初始化代码完全一致(LTDC + DMA2D)
- 触摸驱动使用相同的I2C时序
- 帧缓冲都放在SDRAM中
- 编译器使用ARM GCC 10.3,优化等级 -O2
你可能会问:“为什么不用更高级的硬件?”——我故意的。低端硬件才能放大差异。在高端芯片上大家都跑满60 FPS,那还比什么?
4.3 官方Demo的选择
每个框架都有自己的“看家Demo”。我挑了三个典型场景:
| Demo名称 | TouchGFX版本 | LVGL版本 | 测试重点 |
|---|---|---|---|
| Widget Gallery | TouchGFX Designer 4.22 | LVGL v8.3.10 | 基础控件渲染速度 |
| Chart Demo | TouchGFX 自带图表例程 | lv_chart 官方例程 | 数据刷新与重绘 |
| Animation Showcase | TouchGFX 动画例程 | lv_anim 官方例程 | 复杂动画流畅度 |
这三个Demo基本覆盖了日常开发中80%的场景。Widget Gallery测的是“静态界面”,Chart Demo测的是“动态数据”,Animation Showcase测的是“交互动画”。
4.4 测量方法:别被“假帧”骗了
测量帧率不是简单地数数。我见过有人用HAL_Delay(1000)然后数帧数——这方法太粗糙了。正确的做法是:
- 使用硬件定时器打时间戳:在每帧渲染开始和结束时记录TIM计数值
- 计算帧间隔:帧间隔 = 结束时间 - 开始时间
- FPS = 1000 / 帧间隔(ms):注意,这里取的是瞬时帧率,不是平均
- 连续采样1000帧:记录最大值、最小值、平均值和标准差
下面是TouchGFX的帧率测量代码片段:
// TouchGFX 帧率测量
volatile uint32_t frame_start = 0;
volatile uint32_t frame_end = 0;
volatile uint32_t frame_interval = 0;
void HAL::tick()
{
frame_start = TIM2->CNT; // 帧开始时间戳
// ... 执行渲染 ...
frame_end = TIM2->CNT; // 帧结束时间戳
frame_interval = frame_end - frame_start;
// 通过串口发送原始数据
printf("%lu\n", frame_interval);
}
LVGL的测量方式类似,但要注意LVGL的渲染是异步的:
// LVGL 帧率测量
static uint32_t lvgl_frame_start = 0;
static uint32_t lvgl_frame_end = 0;
void lv_timer_handler(void)
{
lvgl_frame_start = TIM2->CNT;
lv_task_handler(); // LVGL核心处理
lvgl_frame_end = TIM2->CNT;
printf("%lu\n", lvgl_frame_end - lvgl_frame_start);
}
4.5 测试结果:数据说话
好了,直接上数据。每个Demo跑3次,取平均值。环境温度25°C,开发板未加散热片。
| Demo | TouchGFX (FPS) | LVGL (FPS) | 差异 |
|---|---|---|---|
| Widget Gallery | 58.2 | 51.7 | TouchGFX 快 12.6% |
| Chart Demo | 42.5 | 36.8 | TouchGFX 快 15.5% |
| Animation Showcase | 55.1 | 48.3 | TouchGFX 快 14.1% |
嗯,结果很明显。TouchGFX在三个场景下都领先,尤其是在Chart Demo这种需要频繁重绘的场景,优势更明显。为什么?
我个人分析,原因有三:
- TouchGFX使用DMA2D硬件加速:图像混合、颜色格式转换都由硬件完成,CPU几乎不参与
- TouchGFX的局部刷新更激进:它只重绘变化区域,而LVGL在某些场景下会重绘整个屏幕
- TouchGFX的渲染管线是预编译的:所有UI在PC上就编译好了,运行时直接执行,省去了解析布局的时间
但别急着下结论。LVGL在Widget Gallery中其实也跑到了51.7 FPS,对于大多数应用来说,这个帧率已经够用了。而且LVGL的灵活性是TouchGFX比不了的——你想想看,TouchGFX的UI必须用PC工具生成,而LVGL可以纯代码手写。
4.6 帧率波动分析
平均帧率只是表象。真正影响体验的是“帧率稳定性”。我记录了Animation Showcase的帧间隔分布:
看到了吗?LVGL的最大帧间隔是35.1ms,而TouchGFX只有22.3ms。这意味着LVGL在某些帧上会“卡”一下。我在项目中遇到过类似情况——LVGL在加载字体或图片时,会触发一次全屏刷新,导致帧率瞬间掉到30 FPS以下。
4.7 影响帧率的隐藏因素
除了框架本身,还有几个“隐形杀手”会影响帧率:
- 帧缓冲大小:320x240x16bit = 150KB。如果使用双缓冲,就是300KB。内部SRAM不够的话,放SDRAM里会慢10-20%
- 颜色格式:RGB565比ARGB8888快一倍,因为数据量减半
- 屏幕接口:LTDC > FMC > SPI。SPI屏幕的帧率上限通常只有30 FPS
- 编译器优化:-O0和-O2的帧率差异可能达到20%
嗯,这些因素在对比测试中必须统一。否则你测出来的不是框架差异,而是配置差异。
4.8 小结:帧率不是唯一标准
TouchGFX在帧率上确实有优势,尤其是在硬件加速和局部刷新方面。但LVGL的帧率也足够应对大多数场景。我个人的建议是:
- 如果你的硬件有DMA2D,且UI固定不变,选TouchGFX
- 如果你需要频繁修改UI,或者硬件没有图形加速,选LVGL
- 如果帧率要求超过50 FPS,优先考虑TouchGFX
- 如果帧率在30-45 FPS就能接受,LVGL完全够用