第二篇:Flutte 渲染之 Vsync 信号
Vsync 信号可同步显示流水线,协调显示器、CPU 和 GPU 的工作。
显示器按一定频率从 GPU 获取数据,就可以完成图像的更新。现在手机屏幕一般有60HZ、90HZ、120HZ,以60HZ为例,屏幕每秒会发出 60 个 VSync 垂直同步信号。
GPU 每秒可以绘制的帧数叫做帧速率,如果帧速率大于屏幕刷新率,屏幕上显示的内容就有可能是两个图像的不完全内容,造成图像撕裂。
画面撕裂(Screen Tearing)是指显示器把两个或更多的帧(frame)显示在同一画面上所产生的撕裂现象。 以前,屏幕的刷新率是固定的,通常是60Hz。现在显卡性能大幅提高,游戏时输出的帧率可以非常高,如果显卡的输出高于60fps,两者不同步,画面便会撕裂。
VSync 垂直信号可以保证刷新频率的统一。
在 VSync 信号的调度下,UI 系统把逻辑代码变成图像显示到屏幕上,一般需要经过以下几个阶段:
- 1.View,构建 View/DOM 节点
- 2.Layout,计算样式(Style)、布局(Layout)
- 3.ViewTree,将 View 节点按一定规则归属到不同的图层,构建或更新 ViewTree
- 4.Paint,绘制,输出绘制指令到 DisplayList
- 5.Rasterization,光栅化,执行 DisplayList 中的绘图指令,生成图层区域的像素数据
- 6.Composite,合成,把各图层光栅化后的数据进行叠加和特性处理,输出到屏幕上
简单来说就是做了两件事情:
- 构建 UI 描述规则,用于构建或刷新图像,并把绘制指令保存起来用于绘制,即 1-4
- 光栅化和合成,对硬件绘制 API 做了统一封装,屏蔽底层绘制细节,即 5-6
Android 和 iOS 基本都是按照这个流程来构建UI的。Flutter 作为一款跨端 UI 开发框架,它的渲染流程也是类似的。
UI渲染概览
通过VSYNC信号使UI线程和GPU线程有条不紊的周期性的渲染界面,如下图所示:
- 当需要渲染则会调用到 Engine 的 ScheduleFrame() 来注册 VSYNC 信号回调,一旦触发回调 doFrame()执行完成后,便会移除回调方法,也就是说一次注册一次回调;
- 当需要再次绘制则需要重新调用到 ScheduleFrame() 方法,该方法的唯一重要参数regenerate_layer_tree 决定在帧绘制过程是否需要重新生成layer tree,还是直接复用上一次的layer tree;
- UI线程的绘制过程,最核心的是执行 WidgetsBinding 的 drawFrame() 方法,然后会创建 Layer tree 视图树
- 再交由 GPU Task Runner 将 layer tree 提供的信息转化为平台可执行的GPU指令。
VSync 信号注册
在 Flutter App 启动过程或者 State 刷新过程中,会请求注册 VSync 信号。
App 的启动过程
此部分内容不过多阐述,具体可参考:Flutter运行机制-从启动到显示
Vsync 注册流程
此部分内容不过多阐述,具体可参考:Flutter渲染机制—UI线程
参阅
转载自:https://juejin.cn/post/6938221819002519583