渲染管线优化:CPU渲染与GPU渲染的区别
做嵌入式GUI优化,绕不开一个核心问题:谁在干活。CPU还是GPU?我见过不少团队,一上来就堆GPU加速,结果功耗爆炸,帧率反而没上去。说白了,你得先搞清楚这两兄弟的分工。
CPU渲染 vs GPU渲染
CPU是"全能工兵",什么都能干,但一次只能干一件事。GPU是"画图流水线",擅长并行处理大量简单计算。在GUI渲染里,CPU负责构建绘制命令,GPU负责执行绘制命令。
| 对比项 | CPU渲染 | GPU渲染 |
|---|---|---|
| 核心优势 | 灵活,适合复杂逻辑 | 并行,适合大量像素填充 |
| 瓶颈 | 单线程串行,容易卡顿 | 带宽受限,纹理上传慢 |
| 典型场景 | 矢量图形、文字渲染 | 图片缩放、动画过渡 |
| 功耗 | 低(但占用高时发热) | 高(尤其频繁切换状态) |
我在一个智能手表项目里遇到过:用CPU渲染圆形表盘指针,每帧要计算几十个三角函数,CPU占用直接飙到80%。后来改成GPU渲染,把指针预渲染成纹理,帧率从25fps跳到60fps。嗯,这里要注意:不是所有场景都适合GPU。如果你的UI大部分是静态文字,CPU反而更省电。
核心原则:CPU做"少而精"的绘制命令组装,GPU做"多而快"的像素填充。两者配合,才能流畅。
减少绘制调用(Draw Call)
Draw Call是什么?说白了,就是CPU告诉GPU"你该画这个了"的一次通信。每次通信都有开销——CPU要打包数据,GPU要解析命令。你想想看,一帧里如果有几百次Draw Call,光通信开销就把帧率吃掉了。
我习惯用合并绘制的思路。举个例子:一个按钮有背景、边框、文字、阴影,如果分开画就是4次Draw Call。合并成一张纹理,一次搞定。
实战技巧:在LVGL或TouchGFX里,开启"脏矩形"(Dirty Rect)机制。只重绘变化区域,而不是全屏刷新。我见过有人把全屏刷新从60fps降到30fps,就是因为没开这个。
我曾经在一个车载仪表盘项目里,把Draw Call从200+降到30以下。怎么做的?
- 合并静态元素:背景、刻度、固定图标,预渲染成一张大纹理。
- 分层更新:只有指针和数字是动态的,单独一层。
- 避免透明叠加:透明混合会打断批处理,能用不透明就用不透明。
批处理(Batching)技术
批处理,就是把多个相似的绘制命令打包,一次发给GPU。就像你去快递站寄包裹,一个一个寄很慢,攒一箱一起寄就快多了。
批处理的关键是状态一致性。GPU切换状态(纹理、着色器、混合模式)很费时。如果你画10个按钮,每个按钮纹理不同,那就没法批处理。反过来,10个按钮用同一张纹理,一次搞定。
注意:批处理不是万能的。如果UI元素层级复杂,强行批处理反而会增加CPU的排序开销。我建议:批处理只用于同一层级的同类元素。
我常用的批处理策略:
- 纹理图集(Texture Atlas):把所有小图标拼成一张大图。这样切换图标时不用换纹理。
- 顶点缓冲(Vertex Buffer):把顶点数据一次性上传到GPU,避免每帧重复上传。
- 实例化绘制(Instancing):适合大量重复元素,比如列表项、网格。
纹理压缩与格式选择
纹理是GUI的"内存大户"。一张1080p的RGBA8888纹理,占8MB。嵌入式设备内存本来就紧,你想想看,放几张图就爆了。
纹理压缩,说白了就是用更少的比特存更多的像素。但压缩有代价:质量下降、解码开销。怎么选?
| 格式 | 压缩比 | 质量 | 适用场景 |
|---|---|---|---|
| RGBA8888 | 无压缩 | 最高 | 照片、渐变背景 |
| RGB565 | 2:1 | 中 | 图标、纯色块 |
| ETC2 | 4:1 | 高 | Android设备通用 |
| PVRTC | 4:1 | 中 | PowerVR GPU专用 |
| ASTC | 可变 | 可调 | 高端嵌入式GPU |
我在一个智能家居面板项目里,把所有图标从RGBA8888转成RGB565,内存占用降了一半,肉眼几乎看不出区别。但注意:带透明通道的图标,别用RGB565,否则边缘会有锯齿。用RGBA4444或者ETC2带Alpha。
我的习惯:纹理格式选型三步走——1. 看GPU支持什么(查手册);2. 看UI元素类型(照片/图标/文字);3. 看内存预算。别盲目追求高质量,够用就行。
知识体系总览
下面这张图,把本章的核心逻辑串起来了。你可以把它当作优化时的检查清单。
这张图把本章的四个知识点串成了一条优化链路。从CPU/GPU分工开始,到减少Draw Call,再到批处理,最后用纹理压缩收尾。每一步都指向同一个目标:让每一帧的渲染开销最小化。
总结一句话:渲染管线优化的本质,就是减少CPU和GPU之间的无效通信,让它们各司其职、高效协作。别让CPU等GPU,也别让GPU等CPU。