1、双缓冲基础概念:什么是屏幕撕裂、单缓冲的痛点、双缓冲核心思想
屏幕撕裂——你肯定见过,只是不知道它叫啥
先问个问题:你玩手机或看视频时,有没有遇到过屏幕中间出现一条“错位线”?上半张画面还在滚动,下半张已经切到下一帧了。像一张纸被撕开再拼回去,对不上。
这就是屏幕撕裂(Tearing)。我最早在嵌入式项目里遇到它,还以为是屏坏了。后来才发现,是显存和屏幕刷新不同步搞的鬼。
屏幕撕裂怎么发生的?说白了:
- 屏幕每秒刷新 60 次(60Hz),每次刷新从显存读一帧数据。
- CPU/GPU 也在往显存写新帧。
- 如果屏幕读到一半,显存里的数据被新帧覆盖了——好了,上半截是旧帧,下半截是新帧。
你想想看,这就像你在黑板上写字,有人一边擦一边写,你抄到一半,内容变了。抄下来的东西能不乱吗?
核心结论:屏幕撕裂的根本原因是——一个显存区域同时被写入和读取,没有隔离。
单缓冲——最直接的方案,也是最痛的方案
早期嵌入式系统怎么做显示?就一块显存(Frame Buffer),CPU 直接往上画,LCD 控制器直接从里面读。这叫单缓冲。
单缓冲的流程很简单:
- CPU 清空显存。
- CPU 绘制新画面。
- LCD 控制器读取显存并显示。
- 回到第 1 步。
听起来没毛病?我在项目里踩过这个坑。单缓冲有三个硬伤:
| 痛点 | 表现 | 后果 |
|---|---|---|
| 屏幕撕裂 | CPU 绘制中,LCD 开始读 | 画面错位、闪烁 |
| 绘制延迟 | CPU 画完前,屏幕只能显示旧帧或残影 | 操作卡顿、跟手性差 |
| 帧率受限 | 绘制和刷新串行执行 | 帧率上不去,动画不流畅 |
我曾经在一个 240×320 的小屏上做菜单动画,单缓冲下帧率只有 15fps。翻页时画面撕裂得像碎纸机吐出来的。用户反馈说“这设备反应好慢”。嗯,其实不是慢,是显存打架。
避坑指南:单缓冲在低分辨率、静态界面下还能凑合。一旦涉及动画、滑动、视频播放,必出问题。我建议你从一开始就别在交互类产品上用单缓冲。
双缓冲核心思想——给显存加个“后台”
双缓冲的思路其实很朴素:准备两块显存区域。
- 前台缓冲(Front Buffer):LCD 控制器正在读的那块,负责显示。
- 后台缓冲(Back Buffer):CPU/GPU 正在画的那块,负责绘制。
绘制和显示不再抢同一块内存。CPU 在后台画完了,通过一个叫“交换(Swap)”的动作,把前后台角色互换。LCD 读新的前台,CPU 画新的后台。
你想想看,这就像厨房里两个厨师:一个在备菜(后台),一个在出菜(前台)。备好了喊一声“换”,前台把菜端出去,后台继续备下一道。互不干扰。
个人经验:我习惯把双缓冲比作“乒乓缓冲”。两块 buffer 像乒乓球一样来回切换。你打过去,我打回来,永远有一块是稳定的显示画面。
双缓冲解决了什么?
双缓冲直接干掉了两个核心痛点:
- 消除屏幕撕裂:LCD 始终读完整的前台缓冲,不会被后台绘制打断。
- 提升绘制效率:CPU 不用等屏幕刷新,画完就切,切完继续画下一帧。
但双缓冲不是免费的。代价是:
- 内存翻倍:需要两倍的显存空间。
- 交换时机敏感:如果交换发生在屏幕刷新中间,还是会出现撕裂——所以需要配合“垂直同步(VSync)”。
我记得第一次在 STM32 上实现双缓冲时,显存从 64KB 涨到 128KB,MCU 内部 RAM 直接爆了。后来换成外部 SRAM 才搞定。嗯,这里要注意:选型时就要算好显存预算。
一张图看懂单缓冲 vs 双缓冲
下面这张 SVG 图展示了两种方案的流程对比。我建议你仔细看箭头走向,能直观理解“为什么双缓冲不撕裂”。
双缓冲的两种交换策略
双缓冲不是“有两块 buffer 就完事了”。交换时机很关键。我归纳了两种主流策略:
| 策略 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 立即交换 | 后台画完立刻切换前台 | 响应快,延迟低 | 可能撕裂(需 VSync 配合) |
| 垂直同步交换 | 等屏幕消隐期(VBlank)再交换 | 彻底消除撕裂 | 增加 1 帧延迟 |
我个人习惯在触摸交互场景用“立即交换 + VSync”。为什么?因为触摸要求低延迟,VSync 保证不撕裂,两者结合最稳。纯显示场景(比如播放视频)用垂直同步交换就够了。
一句话总结:双缓冲的核心就是“读写分离,整帧交换”。两块 buffer 各司其职,通过交换动作完成角色切换。这是所有现代图形系统的基础。
本章小结
- 屏幕撕裂:显存同时被读写导致的画面错位。
- 单缓冲痛点:撕裂、延迟、帧率低,不适合交互场景。
- 双缓冲核心:前台显示 + 后台绘制,交换角色实现无撕裂渲染。
- 交换策略:立即交换 vs 垂直同步交换,按场景选型。