当前位置: 首页 > news >正文

VSync 信号、BufferQueue 机制和 SurfaceFlinger 的合成流程

可以把整个Android的图形显示过程想象成一个高效的动画制作工厂,这个工厂的目标就是在屏幕上播放一帧接一帧的画面(比如60帧/秒)

一. VSync 信号 - 工厂的节奏大师

VSync(Vertical Synchronization,垂直同步)信号就像是一个节拍器或者工厂的指挥,它以一种非常稳定、精确的节奏发出“滴答”声。这个“滴答”声规定了两个最重要的时间点:

  • 什么时候开始绘制下一帧画面(App绘制节奏)
  • 什么时候必须把准备好的画面显示到屏幕上(屏幕刷新节奏)

在标准的60Hz屏幕上,这个“滴答”声每秒响60次,每次间隔约16.6毫秒

为什么需要它?

如果没有这个节拍器,工厂的各个部门(App绘制和屏幕显示)就会各自为政,混乱不堪。最典型的问题就是屏幕撕裂(Tearing):即屏幕上半部分还显示着上一帧的画面,下半部分却已经拉取了新的一帧画面开始显示了。VSync信号就是为了让所有操作同步,避免这种不和谐的情况

在Android中的具体角色:

Android系统中有两种VSync信号:

  • App VSync (VSYNC-app): 告诉应用程序:“节拍到了,现在可以开始绘制下一帧了!” 这驱动了UI线程的measurelayoutdraw
  • SurfaceFlinger VSync (VSYNC-sf): 告诉SurfaceFlinger合成器:“节拍到了,现在该把所有准备好的画面合成了!” 这驱动了合成的开始

总结:VSync是整个图形系统的心脏起搏器,它规定了所有操作的步调和节奏

二. BufferQueue - 生产和消费之间的传送带

BufferQueue是连接生产者(Producer)(如App)和消费者(Consumer)(如SurfaceFlinger)的一个共享队列。它就像是一条有三节传送带的流水线

这条传送带(BufferQueue)上通常放着三个缓冲槽(Buffer Slot),每个槽里可以放一帧图像数据(GraphicBuffer)

  • 生产者(App) 在传送带的末端dequeued状态)取一个空槽,装满它生产的图像(变成queued状态),然后把它放回传送带
  • 消费者(SurfaceFlinger) 在传送带的前端取一个已经装满的槽(变成acquired状态),把里面的货物(图像数据)拿走使用,用完后把空槽清理干净(变回dequeued状态),再放回传送带的末端,等待生产者再次使用

Buffer的状态:

  • Free / Dequeued: 空缓冲区,生产者可以获取并绘制
  • Queued: 生产者已绘制完成,放入队列等待消费者使用
  • Acquired: 消费者已取走,正在使用(合成或显示)中
  • Posted: 消费者已使用完毕,释放回队列,变回Free状态

为什么需要它?

  • 解耦(Decoupling): 生产者和消费者不需要知道对方的存在,也不需要互相等待。App可以尽情地生产帧(只要还有空缓冲区),SurfaceFlinger也可以在有准备好的帧时立刻进行合成。这极大地提高了效率
  • 防止撕裂(Tearing): 消费者(显示)永远只使用已经完全准备好的缓冲区,而不会去读一个正在被生产者绘制的半成品缓冲区。这就是双缓冲/三缓冲机制的核心

总结:BufferQueue是图形系统中最重要的基石,它用一种高效、安全的方式实现了生产者(App)和消费者(显示)之间的数据共享和解耦

三. SurfaceFlinger 合成流程 - 最后的装配车间

SurfaceFlinger是Android的显示合成器。它的工作就像是一个装配车间的老师傅

它的面前有很多个传送带(BufferQueue),每条传送带都来自一个不同的应用程序或界面层(比如状态栏、导航栏、Activity界面、壁纸等)。每条传送带都会源源不断地送来它们各自绘制好的画面(Buffer)

老师傅(SurfaceFlinger)的工作就是:

  1. 等待指令(VSYNC-sf): 他听着节拍器(VSync信号)。节拍一响,他就开始一次新的工作循环
  2. 收集物料(acquireBuffer): 他去每条传送带的前端看看,如果有已经准备好的画面(Buffer),就拿过来
  3. 设计装配图(计算合成): 他根据客户的订单(每个Layer的位置、大小、透明度、Z-order等属性),决定如何把这些画面一层层地叠起来。比如先把壁纸铺底,然后盖上App的窗口,最后在最上面贴上状态栏
  4. 装配(compose):
    ○ 过去(低效方式):
     老师傅用CPU把所有的画面数据拷贝、混合到一起,生成一张最终的大图(FrameBuffer)。这个过程很耗CPU资源
    ○ 现在(高效方式): 老师傅现在有个厉害的助手叫GPU(或者更专业的硬件合成器HWC)。老师傅只需要告诉GPU:“你把A画面放在(0,0)位置,B画面放在(100,100)位置,C画面半透明...” ,GPU就会以极高的并行速度完成这个“拼图”工作,几乎不消耗CPU资源。HWC是手机SoC里的一个专用硬件模块,做合成这件事比GPU还省电
  5. 送出成品(postBuffer): 装配好的最终画面会被送到另一个最终的传送带上(显示设备的FrameBuffer)。然后屏幕在下一个VSync信号到来时,就会把这幅最终画面拉走并显示出来

总结:SurfaceFlinger是一个协调者,它收集所有UI层的输出,并利用GPU或HWC硬件,高效地将它们合成为最终要显示的一帧图像

三者如何协同工作?一个完整的故事

假设屏幕是60FPS,我们来看一帧画面是如何诞生的:

  1. VSYNC-app信号到来: 节拍器“滴答”一声。App听到后开始行动,从BufferQueue里申请一个空缓冲区(Buffer),开始绘制它的UI(执行onDraw
  2. App绘制完成: App在16.6ms内画完了,它将画好的缓冲区放回BufferQueue队列里,然后就可以休息,等待下一个节拍
  3. VSYNC-sf信号到来: 节拍器又一次“滴答”(可能是同一个信号,但在软件上是错开的)。SurfaceFlinger老师傅听到后开始工作
  4. SurfaceFlinger合成: 老师傅去所有应用的BufferQueue里取已经画好的缓冲区,连同系统UI的缓冲区一起,交给HWC或GPU去合成
  5. 显示: 合成好的最终图像被送到屏幕。紧接着,下一个VSync信号到来,屏幕将这个最终图像显示出来。同时,这个信号又开启了下一个周期,App开始绘制下一帧

整个过程如此循环往复,从而实现了流畅的视觉体验

简单概括:

  • VSync 规定了 “何时” 做
  • BufferQueue 提供了 “何物” (数据)并解决了数据交换问题
  • SurfaceFlinger 负责 “如何做” (合成并显示)

文章转载自:

http://aydAJAL2.Lcxzg.cn
http://tJKN4Cle.Lcxzg.cn
http://XxqQam6e.Lcxzg.cn
http://VMVDZASX.Lcxzg.cn
http://l4YA306H.Lcxzg.cn
http://U0o6qJUX.Lcxzg.cn
http://ppWSQ4Vf.Lcxzg.cn
http://siiFhwpc.Lcxzg.cn
http://HN0WS8Ha.Lcxzg.cn
http://5ftGedX2.Lcxzg.cn
http://wqmp5AQt.Lcxzg.cn
http://gvpRvVpn.Lcxzg.cn
http://a5pm9zy5.Lcxzg.cn
http://uvtnEb9b.Lcxzg.cn
http://Hz7Khh8q.Lcxzg.cn
http://LjndIXq8.Lcxzg.cn
http://fHPDBmPN.Lcxzg.cn
http://N7vEPAZt.Lcxzg.cn
http://bpPhErzi.Lcxzg.cn
http://c4xDFNHf.Lcxzg.cn
http://Wk3u8Nng.Lcxzg.cn
http://aizCJmAO.Lcxzg.cn
http://JztGcyrO.Lcxzg.cn
http://cFlyGOqu.Lcxzg.cn
http://BWpfj5Wm.Lcxzg.cn
http://kbGsLXR4.Lcxzg.cn
http://ik0Fnoyh.Lcxzg.cn
http://26o579Io.Lcxzg.cn
http://tiUGRql5.Lcxzg.cn
http://5E4pz5Pi.Lcxzg.cn
http://www.dtcms.com/a/365868.html

相关文章:

  • 鸿蒙UI开发实战:解决布局错乱与响应异常
  • More Effective C++ 条款26:限制某个类所能产生的对象数量
  • MySQL 第十章:创建和管理表全攻略(基础操作 + 企业规范 + 8.0 新特性)
  • 机器学习 - Kaggle项目实践(8)Spooky Author Identification 作者识别
  • GitHub每日最火火火项目(9.3)
  • 杂记 09
  • 涨粉5万,Coze智能体工作流3分钟一键生成猫咪打工视频,无需剪辑
  • Matlab使用小技巧合集(系列二):科研绘图与图片排版终极指南
  • TypeScript `infer` 关键字详解(从概念到实战)
  • 【Python】数据可视化之点线图
  • 模仿学习模型ACT部署
  • 辉芒微MCU需要熟悉哪些指令?这15条核心指令与入门要点必须掌握
  • Linux gzip 命令详解:从基础到高级用法
  • Python基础(①①Ctypes)
  • C 内存对齐踩坑记录
  • 【随手记】vscode中C语言满足KR风格的方法
  • Elasticsearch核心数据类型
  • 深度学习——卷积神经网络
  • AI产品经理面试宝典第84天:RAG系统架构设计与优化策略面试指南
  • 分布式AI算力系统番外篇-----超体的现世《星核》
  • 【Doris入门】Doris数据表模型使用指南:核心注意事项与实践
  • 从PkiAsn1Decode函数到ASN1Dec_SignedDataWithBlobs函数
  • 中山AI搜索优化实践:技术干货解析与金拓智能案例
  • select, poll, epoll
  • 【108】基于51单片机智能输液监测系统【Proteus仿真+Keil程序+报告+原理图】
  • 详尽 | Deeplabv3+结构理解
  • CSS中使用 HSL(Hue, Saturation, Lightness) 动态生成色值
  • 二叉树结尾——销毁,层序遍历与判断完全二叉树
  • python如何解决html格式不规范问题
  • windows系统服务器测试部署springboot+vue+mysql项目