打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Flutter 渲染机制——GPU线程渲染
userphoto

2022.10.20 上海

关注

Flutter 的方式,实际上的渲染过程不依赖于原生,而是通过 C/C++编写的 Skia 渲染引擎完成界面渲染的。绘制界面的Dart 代码会被编译成原生代码,但是使用的是 Skia 完成渲染。Flutter 内置了 Skia 渲染引擎,使得即便是用户的手机没有更新到最新版本的手机操作系统也能够保持最新的渲染性能。

执行Flutter引擎中图形相关代码(Skia),这个线程通过与GPU通信,获取Layer Tree并执行栅格化以及合成上屏等操作,将Layer Tree显示在屏幕上。
GPU线程流程

1.1 GPU线程的绘制流程图

GPUDraw

Flutter渲染机制在UI线程执行到compositeFrame()过程经过多层调用,将栅格化的任务Post到GPU线程来执行。GPU线程一旦空闲则会执行Rasterizer的draw()操作。图中LayerTree::Paint()过程是一个比较重要的操作,会嵌套调用不同layer的Paint过程,比如TransformLayer,PhysicalShapeLayer,ClipRectLayer,PictureLayer等都执行完成会执行flush()将数据发送给GPU。

1.2 Surface类图

ClassSurface


ClassSurface

三种不同的AndroidSurface,见小节2.6.3,说明如下:

  • 硬件VSYNC方式,且开启VULKAN,则采用AndroidSurfaceVulkan,这是当前默认的方式;

  • 硬件VSYNC方式,且未开启VULKAN,则采用AndroidSurfaceGL;

  • 使用软件模拟的VSYNC方式,则采用AndroidSurfaceSoftware;

1.3 Layer类图

ClassLayer

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线程在引擎和框架的绘制工作。



    当需要渲染则会调用到Engine的ScheduleFrame()来注册VSYNC信号回调,一旦触发回调doFrame()执行完成后,便会移除回调方法,也就是说一次注册一次回调;
    当需要再次绘制则需要重新调用到ScheduleFrame()方法,该方法的唯一重要参数regenerate_layer_tree决定在帧绘制过程是否需要重新生成layer tree,还是直接复用上一次的layer tree;
    UI线程的绘制过程,最核心的是执行WidgetsBinding的drawFrame()方法,然后会创建layer tree视图树,再交由GPU Task Runner将layer tree提供的信息转化为平台可执行的GPU指令。

    Flutter线程模型

    Embedder中存在四个Runner,四个Runner分别如下。其中每个Flutter Engine各自对应一个UI Runner、GPU Runner、IO Runner,但所有Engine共享一个Platform Runner。

 

GPU Runner

GPU Runner并不直接负责渲染操作,其负责GPU相关的管理和调度。当layer tree信息到来时,GPU Runner将其提交给指定的渲染平台,渲染平台是Skia配置的,不同平台可能有不同的实现。
GPU Runner相对比较独立,除了Embedder外其他线程均不可向其提交渲染信息。

文末

本文结合Flutter的官方描绘的框架和渲染流程,简要介绍了渲染的过程实现方式,让读者对Flutter在渲染方面有基本的理解,便于以后的开发和探索。为Flutter生态作出一点自己的贡献,期待Flutter越来越好!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
聊一聊Flutter Engine线程管理与Dart Isolate机制
Flutter图像绘制原理深入分析
跨平台Web Canvas渲染引擎架构的设计与思考
Chromium网页渲染调度器(Scheduler)实现分析 vsync信号
iOS 保持界面流畅的技巧 | Garan no dou
字节跳动Flutter架构实践
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服