
微信交流群
作者:易旭昕
写作费时,敬请点赞,关注,收藏三连。
Flutter 渲染引擎在 iOS 上的实现请参考我的文章 Flutter 渲染引擎详解 - iOS Metal 篇。
Flutter 渲染引擎在 Android 上也支持三种渲染方式,分别是纯软件(CPU),GL 和 Vulkan。其中纯软件模式是运行时由 Settings 的 enable_software_rendering 开关控制,默认为 false,目前只看到是通过命令行开关来控制,猜测是用于特定的测试用途。
跟 iOS 不一样的是,Flutter 在 Android 上并不是动态判断系统和硬件环境,在运行时来选择 Vulkan 或者 GL,而是需要开发者自行编译一个开启 SHELL_ENABLE_VULKAN 宏的 Flutter Engine,可能 Skia 对 Vulkan 在 Android 上的支持还不够完善的缘故,这个宏是默认关闭的,所以 Flutter 在 Android 上目前还是以 GL 为主。
这篇文章的主要内容是讲解在 Android 上,Flutter 渲染引擎:
- 需要的 GL GPU 上下文环境是如何完成初始化;
- 目标输出 Surface 的设置过程;
- 渲染流水线执行光栅化的调用过程。
上图显示了 Flutter 渲染引擎在 Android 上主要涉及的对象,黄色背景是平台相关的适配对象,白色背景是平台无关的通用对象。后面的内容我们会频繁地引用图中的对象,这张图可以方便读者了解它们之间的关系。
Flutter 在 1.20 之前的版本,Context 和 Surface 这部分的实现存在比较多的 hardcode,代码逻辑比较混乱,1.20 版本做了比较大的重构,整体设计跟 iOS 基本趋同,本文是根据 1.20 的代码写就。
# GL GPU 上下文环境初始化
上图显示了 Android 应用在主线程初始化 Flutter Engine 的调用栈:
- Flutter Engine Native 部分的主要入口在 AndroidShellHolder,它在 engine 初始化的时候被创建;
- AndroidShellHolder 创建 Shell 并持有它;
- Shell 在创建时调用 AndroidShellHolder 提供的 Callback 创建 PlatformViewAndroid 并获得所有权;
- PlatformViewAndroid 在被创建时先创建 AndroidContextGL,然后把它传递给接着创建的 AndroidSurfaceGL,最后 PlatformViewAndroid 持有 AndroidSurfaceGL,AndroidSurfaceGL 持有 AndroidContextGL;
AndroidContextGL 提供了 Flutter 渲染引擎所需要的 GL 上下文环境。它会先创建两个 EGLContext,一个 main context 在 raster 线程用于光栅化,一个 resource context 在 io 线程用于图片纹理上传,因为 main context 是 resource context 的 share context,所以 resource context 上传的纹理可以被 main context 直接使用。AndroidSurfaceGL 在构建时会马上请求 AndroidContextGL 创建 offscreen 的 AndroidEGLSurface。AndroidEGLSurface 是 EGLSurface 的封装,对于 offscreen 来说,只是用一个 1x1 的 PbufferSurface 作为 resource context 的 target EGLSurface,这个PbufferSurface 只是作为必须的占位符,没有实际用途。
AndroidSurfaceGL 构建完毕之后,Flutter 渲染引擎所需要的 GL 上下文环境就已经初始化完成了。跟 iOS Metal 不同的是,因为 GL Context 的线程相关性,Skia GrContext 需要延迟到 GL Context 设置到目标线程真正使用的时候才创建,无法提前创建。
# 设置目标输出 Surface
Flutter 允许应用选择 SurfaceView 或者 TextureView 作为目标输出 Window,无论是选择 SurfaceView 还是 TextureView,Flutter 都是通过注册回调方法,在 SurfaceView/TextureView 可见时获得回调,得到封装了 Android Native Window 的 Surface 对象。
- 当主线程获得系统回调通知 Surface 已经创建时,它会调用 Engine Native 的代码 SurfaceCreated(platform_view_android_jni_impl.cc);
- SurfaceCreated 会取出 Surface 对象里面的 Window Handle,并封装成 AndroidNativeWindow 对象传递给 PlatformViewAndroid::NotifyCreated;
- PlatformViewAndroid::NotifyCreated 在主线程被调用时,会通知 raster 线程,并同步等待结果;
- raster 线程接收到消息后会调用 AndroidSurfaceGL::SetNativeWindow;
- AndroidSurfaceGL::SetNativeWindow 调用 AndroidContextGL::CreateOnscreenSurface;
std::unique_ptr<AndroidEGLSurface> AndroidContextGL::CreateOnscreenSurface(
fml::RefPtr<AndroidNativeWindow> window) const {
EGLDisplay display = environment_->Display();
const EGLint attribs[] = {EGL_NONE};
EGLSurface surface = eglCreateWindowSurface(
display, config_, reinterpret_cast<EGLNativeWindowType>(window->handle()),
attribs);
return std::make_unique<AndroidEGLSurface>(surface, display, context_);
}
2
3
4
5
6
7
8
9
10
11
AndroidContextGL::CreateOnscreenSurface 实际上就是使用 Window Handle 创建对应的 EGLSurface,并包装成 AndroidEGLSurface 返回给 AndroidSurfaceGL 作为光栅化输出的 onscreen EGLSurface。
主线程等待完 raster 线程创建 onscreen EGLSurface 后,再次同步请求 raster 线程调用 PlatformViewAndroid::CreateRenderingSurface,实际上这里就是创建 GPUSurfaceGL。GPUSurfaceGL 被创建时会先请求 AndroidSurfaceGL 将 AndroidContextGL 里面的 main EGLContext 作为 raster 线程的当前 GL 上下文,然后创建对应的 GrContext 并持有。这个 GrContext 将来就会用于光栅化。
主线程同步等待 GPUSurfaceGL 创建完毕后,把获得的 GPUSurfaceGL 对象通过 Shell 传递给 Rasterizer 持有,到这里光栅化器就完成了目标输出 Surface 的设置,现在我们可以开始绘制第一帧了。
# 光栅化输出
关于 Flutter 渲染流水线比较完整的说明请参考我之前的文章 Flutter 渲染流水线浅析,在这里我们只关注光栅化的部分。Flutter 光栅化的过程比较简单,Android 和 iOS 基本流程也是大同小异:
- Rasterizer 请求 GPUSurfaceGL 创建一个 SkSurface,这个 SkSurface 实际上就是当前 EGLContext 的 FBO 0 的包装,也就是之前创建的 onscreen EGLSurface,实际上就是源自 SurfaceView 或者 TextureView 的 Android Native Window;
- 通过上述获得 SkSurface 对象,取得对应的 SkCanvas 对象;
- 将生成的图层树里面的 DisplayList(SkPicture)通过上面的 SkCanvas 逐个绘制到 SkSurface 上,Skia 会先存储经过预处理的 2D 绘图指令;
- Flush SkCanvas,相当于生成相应的 GL GPU 绘图指令请求 GPU 执行;
- 最后调用 eglSwapBuffers 请求 Android Native Window 交换前后台缓冲区,并触发 Android UI 的重绘(TextureView)或者 SurfaceFlinger 的窗口重新合成(SurfaceView);
版权所有,禁止私自转发、克隆网站。
告别setState()! 优雅的UI与Model绑定 Flutter DataBus使用~ Flutter 渲染引擎详解 - iOS GL 篇