前言
记得在13年做群视频通话的时候,多路视频渲染成为了端上一个非常大的性能瓶颈。原因是每一路画面的高速上屏(PresentRenderBuffer or SwapBuffer 就是讲渲染缓冲区的渲染结果呈现到屏幕上)操作,消耗了非常多的CPU和GPU资源。
那时候的解法是将绘制和上屏进行分离,将多路画面抽象到一个绘制树中,对其进行遍历绘制,绘制完成以后统一做上屏操作,并且每一路画面不再单独触发上屏,而是统一由Vsync信号触发,这样极大的节约了性能开销。
那时候甚至想过将整个UI界面都由OpenGL进行渲染,这样还可以进一步减少界面内诸如:声音频谱,呼吸效果等动画的性能开销。但由于各种条件限制,最终没有去践行这个想法。
万万没想到的是这种全界面OpenGL渲染思路还可以拿来做跨平台。
Flutter渲染框架
下图为Flutter的一个简单的渲染框架:
Layer Tree:这个是dart runtime输出的一个树状数据结构,树上的每一个叶子节点,代表了一个界面元素(Button,Image等等)。
Skia:这个是谷歌的一个跨平台渲染框架,从目前IOS和anrdroid来看,SKIA底层最终都是调用OpenGL绘制。Vulkan支持还不太好,Metal还不支持。
Shell:这里的Shell特指平台特性(Platform)的那一部分,包含IOS和Android平台相关的实现,包括EAGLContext管理、上屏的操作以及后面将会重点介绍的外接纹理实现等等。
从图中可以看出,当Runtime完成Layout输出一个Layertree以后,在管线中会遍历Layertree的每一个叶子节点,每一个叶子节点最终会调用Skia引擎完成界面元素的绘制,在遍历完成后,在调用glPresentRenderBuffer(IOS)或者glSwapBuffer(Android)按完成上屏操作。
基于这个基本原理,Flutter在Native和Flutter Engine上实现了UI的隔离,书写UI代码时不用再关心平台实现从而实现了跨平台。