Flutter 的方式,实际上的渲染过程不依赖于原生,而是通过 C/C++编写的 Skia 渲染引擎完成界面渲染的。绘制界面的Dart 代码会被编译成原生代码,但是使用的是 Skia 完成渲染。Flutter 内置了 Skia 渲染引擎,使得即便是用户的手机没有更新到最新版本的手机操作系统也能够保持最新的渲染性能。
执行Flutter引擎中图形相关代码(Skia),这个线程通过与GPU通信,获取Layer Tree并执行栅格化以及合成上屏等操作,将Layer Tree显示在屏幕上。
GPU线程流程
Flutter渲染机制在UI线程执行到compositeFrame()过程经过多层调用,将栅格化的任务Post到GPU线程来执行。GPU线程一旦空闲则会执行Rasterizer的draw()操作。图中LayerTree::Paint()过程是一个比较重要的操作,会嵌套调用不同layer的Paint过程,比如TransformLayer,PhysicalShapeLayer,ClipRectLayer,PictureLayer等都执行完成会执行flush()将数据发送给GPU。
ClassSurface
三种不同的AndroidSurface,见小节2.6.3,说明如下:
硬件VSYNC方式,且开启VULKAN,则采用AndroidSurfaceVulkan,这是当前默认的方式;
硬件VSYNC方式,且未开启VULKAN,则采用AndroidSurfaceGL;
使用软件模拟的VSYNC方式,则采用AndroidSurfaceSoftware;
LayerTree的root_layer来源于SceneBuilder过程初始化,第一个调用PushLayer()的layer便成为root_layer_,后面的调用会形成一个树状结构。从上图,可知ContainerLayer共有9个子类,由这些子类组合成为了一个layer tree,具体的组合方式取决于业务使用方,在LayerTree的Prepoll和Paint过程便会调用这些layer的方法,下面来看看这9个类:
ClipRectLayer:矩形裁剪层,可指定矩形和裁剪行为参数,其中裁剪行为有Clip.none,hardEdge,antiAlias,antiAliasWithSaveLayer四种行为;
ClipRRectLayer:圆角矩形裁剪层,可指定圆角矩形和裁剪行为参数,同上四种行为;
ClipPathLayer:路径裁剪层,可指定路径和裁剪行为参数,同上四种行为;
OpacityLayer:透明层,可指定透明度和偏移量参数,其中偏移量是指从画布坐标系原点到调用者坐标系原点的偏移量;
ShaderMaskLayer:着色层,可指定着色器、矩阵和混合模式参数;
ColorFilterLayer:颜色过滤层,可指定颜色和混合模式参数;
Transformayer:变换图层,可指定转换矩阵参数;
BackdropFilterLayer:背景过滤层,可指定背景图参数;
PhysicalShapeLayer:物理形状层,可指定颜色等八个参数。
源码角度来看看Flutter的渲染绘制机制,跟渲染直接相关的两个线程是UI线程和GPU线程:
UI线程:运行着UI Task Runner,是Flutter Engine用于执行Dart root isolate代码,将其转换为layer tree视图结构;
GPU线程:该线程依然是在CPU上执行,运行着GPU Task Runner,处理layer tree,将其转换成为GPU命令并发送到GPU。
通过VSYNC信号使UI线程和GPU线程有条不紊的周期性的渲染界面,本文介绍VSYNC的产生过程、UI线程在引擎和框架的绘制工作。
Embedder中存在四个Runner,四个Runner分别如下。其中每个Flutter Engine各自对应一个UI Runner、GPU Runner、IO Runner,但所有Engine共享一个Platform Runner。
GPU Runner并不直接负责渲染操作,其负责GPU相关的管理和调度。当layer tree信息到来时,GPU Runner将其提交给指定的渲染平台,渲染平台是Skia配置的,不同平台可能有不同的实现。
GPU Runner相对比较独立,除了Embedder外其他线程均不可向其提交渲染信息。
本文结合Flutter的官方描绘的框架和渲染流程,简要介绍了渲染的过程实现方式,让读者对Flutter在渲染方面有基本的理解,便于以后的开发和探索。为Flutter生态作出一点自己的贡献,期待Flutter越来越好!
联系客服