众所周知,Impeller 是 Flutter 全新一代渲染引擎,用于取代 Skia,目标是提供更一致、可预测的图形性能。那么它的优点是什么呢?这就要说一说在flutter中我们进行图像渲染的细节了。
在flutter框架中,widgets tree 是由widget对象组成的,而这些widget对象在内存中自然构成了一个object tree,每个object都包含了如何布局和绘制widget的指令,并存储到display list中,其中所有的内容都会由渲染管线利用GPU渲染到surface texture上。
在绘制图像时,首先,我们会获取display list绘制的所有路径并且将它们细分为三角集。然后,三角形上的每个顶点或者点都会经过Vertext shader(在图形设备上执行的一小段代码,属于flutter 引擎代码库的一部分,我们可以编写自己的shader),在Vertext shader获取到所有的点之后,会把这些点移动到屏幕上我们想要绘制的位置(定位想要绘制的图像)。
完成后我们就开始遍历所有的三角形,对于每一个三角形我们都会找出其中具体的像素(Rastaization 光栅化),,然后对于每个像素我们都会进行一些检查(Stencil Test)以确定我们是否真的需要为其计算颜色。这个检查对Impeller很重要,这也是Impeller性能优化的一个关键点,通过提前过滤掉不需要渲染的像素来减少渲染编译的成本,特别是在处理裁切过的复杂图形上,这种成本的减少是巨大的。
然后三角形中的所有像素都通过Fragment shader利用Vertext shader的输出来进行颜色的计算,然后进行blending 也就是颜色混合,这种混合非常简单,就是进行了颜色替换。
那Impeller中的渲染管线具体是怎么实现的呢?首先Impeller具有分层架构,每一层都使用其下一层来完成其工作。
以上方Logo图标的绘制为例,所有display list 的操作都被分配给了一个叫做Aiks(主要由Canvas的绘图api组成)的东西,Aiks的工作是从display list中获取高级指令(例如绘制路径,绘制图像),并将他们转换为更简单,自包含的绘图操作,称为Entity。Entity包含了每个绘图操作所需的一组属性,比如编码位置,旋转和比例的变换矩阵,以及分配给它们的内容对象(内容对象包含了绘制Entity所需的实际GPU指令)。
由于flutter应用程序可以在许多不同的平台上运行,因此Impeller需要一个转换层(Hardware Abstraction Layer)来与GPU进行通信,它通过各种标准图形的API(iOS:Metal,Android:Vulkan)与图形程序通信。
接下来我们要告诉GPU我们要做什么。每个内容(Entity包含的)都使用Hardware Abstraction Layer来绘制自身,指示GPU执行我们想要使用的着色器渲染管道(前面说过,是在图形设备上执行的一小段代码)。这些命令使用图形API执行,然后将生成的纹理显示在屏幕上。这里有一点,这些着色器渲染管道也需要编译为GPU可以执行的指令,这个过程对于性能的消耗是非常昂贵的。在Skia中,这个编译过程是在运行时的帧上进行的,但是管道是用来渲染的,这就难免会导致框架超出预算,造成卡顿。
Impeller则是通过预编译shader来减少runtime的编译压力。在构建flutter引擎时,所有的Impeller着色器都会使用Impeller的离线着色编译器编译成包,因此flutter可以完全控制其渲染图形的方式。同时,flutter使用了替代渲染技术,使用了一组更小更简单的着色器来减少初始化一堆预编译着色器对于启动时间的影响。
同时Impeller 将渲染拆分为两个主要线程:
- Raster 线程:负责构建 GPU 命令缓冲区,将 DisplayList 中的绘制命令转换为 GPU 指令(绑定纹理、绘制调用等)。
- Compositor 线程:负责合成多个图层、处理转换操作,并最终提交渲染结果到 GPU。
这种分工有效减少 CPU–GPU 间同步停顿,保持帧率稳定 。
当Flutter 中的渲染命令被记录进 DisplayList后,Impeller 持久化这些命令,并按 tile进行 GPU 缓存与复用。屏幕被切分成多个 tile,仅当某个tile内容改变时,Impeller 才重新渲染该部分。内容未变的 tile 会复用之前的 GPU buffer,无需再提交绘制命令,优化性能。
综上所述,Impeller 作为 Flutter 的新一代渲染引擎,通过一整套自定义的渲染管线与架构设计,极大提升了图形渲染的性能与一致性。它不仅采用了预编译 shader、轻量着色器与 tile-based 缓存机制减少运行时开销,还通过引入多线程架构解耦 CPU 与 GPU 的负担,避免了 Skia 在实时编译与资源调度上的瓶颈。通过这些优化,Impeller 更加契合现代移动设备的图形处理需求,为 Flutter 应用带来了更加流畅、稳定且可控的渲染体验,也为开发者提供了更大的性能调优空间与跨平台一致性保障。