背景
iot有着很广阔的场景: 艾瑞咨询-积基“数”本、重塑产业:中国物联网行业研究报告-220129. 智慧城市、车联网、智慧零售、智能家居、智能工厂.
- 自动售货机
- 政府政务办理机器
- 医院挂号、缴费、检查报告机 (浙一)
- 车载“科技感”大联屏
越来越方便、随处可见、智能化的设备, 它们的技术方案是什么?
flutter这种技术方案,是否能运用在这些场景之中?
Flutter目前在PC、移动端和web领域站稳跟脚,稳步发展,但是在iot领域, 存在感还不太强.
IOT场景调研
行业case
- Toyota 车载屏幕
- 技术方案
- before: 嵌入式linux
- 船新版本: Custom Flutter Engine Embedders
- Flutter Showcase | Toyota
- 收益
- 性能
- ui动效体验
- 开发体验
- 技术方案
- 梅赛德斯奔驰超联屏
- QT
- 医疗
小结:嵌入式/iot UI框架技术方案
- 嵌入式linux + QT (传统开发出身)
- 性能好点的跑Android (移动互联出身)
- 其它 : 天猫精灵 (js 世界)
Flutter IOT方向探索
- 前期技术探索阶段
- 打卡机实现阶段
技术探索阶段
- Flutter on Android
- Flutter on Linux :
- PC
- 嵌入式
Linux图形栈
嵌入式和pc在图形栈是什么样子的, 后期如何选择合适的方案?
flutter-gtk
linux_graphic
- GTK: Unix-like系統下开发图形界面的应用程序的主流开发工具之一
- 显示服务器(Display Server):
- X11 : 1984年由MIT研发,历史悠久. Server/Client模型,但是由于通信效率、以及老旧设计问题,逐渐被wayland替代 X Window的前生今世
- Wayland: 揭开Wayland的面纱 Compositor/Client模型。(现代化渲染模型),
gtk4将显示后端由x11迁移到wayland,gtk5考虑放弃支持x11
- xxGl : opengl库
- Drm: DRM subsystem in Linux直接渲染管理器。
- Framebuffer: fbdev 的 API ,用于管理显卡的 framebuffer (LCD屏幕显示内存映射)
- Evdev: 管理输入设备:鼠标、键盘、触摸屏, 一般通过libinput库监听各种设备转化后的标准事件.
X Window System
X是规范,不是具体的某个软件, 现在大部分的 distribution使用的X都是由 Xorg 基金会所提供的 X11 软件 . 不是UNIX或Linux内核的一部分,而是用户态的软件组件,用户在系统上可以选择启用或禁用X。
X11采用了client/server的架构,整个图形视窗系统主要分为3个部分:
XClient
(X客户端)。X Client也叫X应用程序,负责实现程序逻辑,在收到设备事件后计算出绘图数据,由于本身没有绘制能力,只能向XServer
发送绘制请求和绘图,告诉X Server在哪里绘制一个什么样的图形。X Client可以和X Server在同一个主机上,也可以通过TCP/IP网络连接。 (Xlib及其替代者XCB)XServer
(X服务器)。X Server一方面负责和设备驱动交互,监听显示器和键盘鼠标,另一方面响应XClient
需求传递键盘、鼠标事件、(通过设备驱动)绘制图形文字等。- Compositor:(合成器)或者叫Window Manager。多个X Client程序并不知道彼此的存在,需要一个管理者统一协调,即Window Manager,它掌管各X Client的Window(窗口)视觉外观,如形状、排列、移动、重叠渲染等. Window Manager并非X Server的一部分,而是一个特殊的X Client程序。(
Metacity、Mutter、KWin、 vtwm、Xfwm、Compiz
)
1 | XDrawLine(display_, x_window_, x_gc_, 0, 0, 50, 50); |
- 优点:
- 模块化设计, X Client和X Server相互独立,并不需要了解彼此所处的硬件、软件环境。
- 90年代初期,gpu还没普及, “X终端机(X terminal)”,专门部署X Server,将远端UNIX主机上的图形界面程序显示出来,这也正是MIT研发X的初衷之一。
- 缺点:
- 频繁的通信, ui太浪费性能
- Xorg大管家管事太多,除了管理input,所有的绘图请求、窗口管理、窗口合成都必须要与Xorg进行交互,导致Xorg上存在性能瓶颈。根源还在于Xorg的架构太复杂。
Wayland
Wayland是一个新的图形窗口系统方案,一套旨在取代X的新规范。与X最大的不同是,Wayland将X中的Server和窗口管理器整合到一起作为服务端,称为合成器(Compositor),架构上只分了客户端和合成器两大部件.
2008年,红帽公司(RedHat)的开发者Kristian Høgsberg利用业余时间搞起了Wayland项目,2010年Wayland加入了http://Freedesktop.org项目
- 客户端(Wayland Client),直接计算各自界面的渲染缓冲数据,客户端程序需要和渲染库(如OpenGL)链接。
- 合成器(Wayland Compositor),汇总所有客户端的渲染数据,实现各界面窗口“合成”,最后交给显示驱动绘图。 Wayland项目提供了两套底层库libwayland-server和libwayland-client,简化图形程序开发,还给了一个Compositor参考实现——Weston。
DRM
DRM 的诞生就是用来处理多个程序对 Video Card 资源的协同使用问题。DRM 获得对 Video Card 的独占访问权限,它负责初始化和维护命令队列、Video RAM 以及其他相关的硬件资源,要使用 GPU 的程序将请求发送给 DRM,由 DRM 作为仲裁来避免冲突。
FrameBuffer
https://en.wikipedia.org/wiki/Linux_framebuffer
Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏, 可以看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的,用户不必关心物理显存的位置、换页机制等等具体细节,这些都是由Framebuffer设备驱动来完成的,
到此,对linux底层图形栈有了全面的了解.
Custom Flutter 移植
官方实现了对linux(gtk)的支持,像ubuntu这类pc系统可以正常run起来. 但是对嵌入式Linux的支持不成熟,ui渲染、库支持、交叉编译工具链、包体积、内存等需要修改定制,sony在官方api的基础上,开源了一个项目,支持flutter 嵌入式.
- 官方定制说明 Custom Flutter Engine Embedders
- sony开源项目flutter-embedded-linux
Flutter架构
平台无关: 跨平台
- dart业务代码
- Flutter framework(Dart)
- Flutter engine
- DartVM
- 渲染
1 | typedef struct { |
特定平台代码 (移植工作)
- 渲染支持 (显示后端)
- Event (输入设备事件)
- 扩展能力(Plugin、外接纹理)
- 生命周期管理(engine/window/view)
Sony开源项目
- lifecycle
1 | FlutterELinuxEngine::RunWithEntrypoint(...){ |
- event
1 | void FlutterELinuxEngine::SendPointerEvent(...) { |
- plugin/Texture
1 | bool FlutterELinuxEngine::SendPlatformMessage(){ |
- render
1 | FlutterELinuxEngine::RunWithEntrypoint(...){ |
- 完成对flutter实例的管理, 启动销毁、渲染更新、事件发送、平台插件能力提供.
- 在具体渲染上屏的时候,选择对应的display backend(wayland、x11、gbm、egl)
产物
技术实现
- 技术需求:
- flutter嵌入式linux支持
- 业务场景:嵌入式linux
- 软件开发技术诉求
- 当前qt方案, 大量c++代码(驱动、视频库), 未来可能切换到Android设备
- 希望一套代码跨端(ui+逻辑)
- 硬件孱弱, 运行性能要求
- 4核 or 1核
- 512m内存
- 没有gpu
- 软件开发技术诉求
- 问题
- 开发版型号未定,硬件性能不确定
- 不确定是哪种渲染方式 Gtk ? x11 ? wayland?
- 确定没有gpu, 必须实现软解方案
第一步 mock环境,预先获得数据
摸清楚当前硬解方案的性能x11 wayland drm
硬件:
- 树莓派2w
- 480x640
数据:
fps | 内存 | cpu (core 4) | |
---|---|---|---|
x11 | 30 | flutter-45% xorg-5% | 300% |
wayland | :— | 35.1% | 5% |
drm | 50-60 | :– | :– |
- x11数据太差
- wayland数据像是bug( 可能是使用姿势问题)
- drm数据超出预期
x11/wayland 是多app窗口形式, drm是独占屏幕模式
适配x11和wayland 软解的成本
skia自身支持软解, 去熟悉flutter、elinux-flutter、以及图形api(x11/wayland), 写代码串联run起来.
- FLUTTER 源码,flutter通过skia 软解获取纹理数据
1 | /skia申请bacbuffer |
- elinux-flutter调用embderapi, 注册渲染数据回调
1 | //软件解码,传过来skia解码后的bitmap |
实现了x11/wayland下的软件解码成本不大, 但是最终没有采用这个方式
- 在实现X11和wayland的软件解码的同时,同时验证的硬件解码的性能数据不太理想: x11 fps 20左右, wayland卡成ppt
- 沟通了合作方的技术方案
- app是全屏独占模式,x11和wayland是窗口模式
- 走的是定制化framebuffer, 不走x11 or wayland
- 继续研究fb下的实现
第二步 正式开发FB
根据业务的硬件和软件情况: 没有GPU,定制显示到framebuffer上. 确定做flutter在嵌入式上直接显示到framebuffer的方案
- 渲染framebuffer
- 事件-evdev
Framebuffer开发介绍
- 红色为Flutter-elinux运行时扩展framebuffer的核心链路代码
- 蓝色是和flutter embder交互的接口
- 橘色为使用linux本地能力的代码 (渲染+event)
- 创建对应渲染后端对应的窗口
1 | std::unique_ptr<flutter::WindowBindingHandler> window_wrapper = |
- 核心逻辑
1 | NativeWindowFrameBuffer::NativeWindowFrameBuffer(...) { |
问题1 处理纹理数据到framebuffer时间过长
OnBitmapSurfaceUpdated 函数耗时过长, 40-50ms左右 1000/50 = 20 fps?
1 | bool NativeWindowFrameBuffer::OnBitmapSurfaceUpdated(...){ |
- 纹理数据的像素格式转换为fb驱动支持的格式: rgba8888->rgb565
- cpu浪费:
- flutter调用skia时, 软解默认写死是rgba8888格式,lcd 不一定需要这么高规格: rgb565, skia调用cpu绘制、纹理化数据的操作,浪费性能
- Framebuffer 消费 数据时,额外对每个像素做一次格式降级,cpu浪费+1. rgba8888->rgb565
- 内存浪费
- rgb565(16位),rgba8888 32位. 2倍内存
解决方法:
- 预先获得格式,让skia按传入格式处理,
- framebuffer消费时直接memcpy就完了
- cp纹理数据到buffer
1 | bool NativeWindowFrameBuffer::OnBitmapSurfaceUpdated(..data){ |
- framebuffer消费数据耗时 50ms->4.1ms
- 纹理内存减半 pixmap_data_size : 4m -> 2m
问题2: 画面撕裂
- 上半部分苹果,下半部分香蕉
- 单缓冲 (1080p屏幕比较明显)
- 双缓冲
1 | void NativeWindowFrameBuffer::SwapBuffers() { |
前台buffer展示, 后台buffer写数据. 轮流切换
- 三缓冲: Android 4.1黄油计划(Project Butter)
目前实现到双缓冲,3缓冲还未支持 Android显示系统之——多缓冲和Vsync
- cpu等待一个vsync(16ms),浪费
- 没有什么是buffer解决不了的,如果不够,那就再加1个!
数据汇总
树莓派数据 | CPU占用% | 内存占用%(512) | fps |
---|---|---|---|
静止 | 99.77 | 7.94 | |
滑动 | 126 | 50-60, 转场20-30 |
总结
目前方案情况
- Core : 核心链路功能完善, 需要做性能优化
- Cli: 将arm64交叉编译构建能力合入
- Deps: 空白. 相关嵌入式上的生态能力补充. widgets、plugin、动态化
在扩展flutter-elinux项目后, 目前flutter针对复杂的linux终端设备类型, 不管从硬件类型还是软件方案,基本可以做到全覆盖:
- 官方: linux pc发行版完全体 gtk
- 嵌入式:
- 硬解 opengl && 软解skia
- 显示后端:
- 轻量版 : 窗口模式. x11、wayland
- 究极精简版: 全屏独占模式 DRM、Framebuffer
场景探索
也就是说,从技术上来说, iot、嵌入式设备上gui方案, flutter在技术上是完全支持,不存在技术障碍,有场景基本可以拎包就上.
和QT目前的状态有点相似, QT作为老牌方案,目前应用已经非常广泛, 见官方宣传图,涉及多个领域和设备类型.
[图片]
既然QT能做,能力相似的Flutter也能做. 并且相比于QT,Fluter有着天然的跨端能力(一套dart代码跨n个端), 更简单的开发语言(dart vs c++), 这是QT无法比拟的. Flutter Linux 调研
类似领域/场景,Why Not Try Flutter?