跳转到内容

演进:Android 先在内核外试新做法,验证后并回上游 DRM

结论:Android 显示栈早期在内核外自建了一整套机制:fbdev 上屏、pmem 和 ION 分配显存、自家 sync 框架做同步、HWC 叠加图层。2015 年以后,这些机制逐个合进上游,或者改用上游的同类机制。 今天 Android 和 Linux 桌面共用 DRM/KMS、dma-buf、sync_file 这一套内核接口。这正是前几篇里“内核以下两边共用”的由来。

两条线的交汇:三次交汇奠定了今天的共用接口

Section titled “两条线的交汇:三次交汇奠定了今天的共用接口”

演进:上游 Linux DRM 与 Android 显示栈的时间线

  • 2012 年前后,两边各自发展。
    • 上游解决的是桌面问题:把显存和显示模式收进内核(GEM、KMS),让不同驱动共享 buffer(dma-buf)。
    • Android 解决的是手机问题:用 HWC 让显示控制器叠加图层来省电,用 VSYNC 和三缓冲保证流畅,用自家的 sync 框架同步 GPU 和显示。
  • 第一次交汇:Android 的 sync 框架合进上游,成为 sync_file。 显式 fence 是 Android 先做出来的,上游 atomic KMS 的 IN_FENCE_FD 和 OUT_FENCE_PTR 直接用了它。
  • 第二次交汇:HWC 改用 atomic KMS 实现。
    • Google 曾在 2013 年前后另做了一套显示框架 ADF,因为当时 KMS 没有原子提交,满足不了 HWC 每帧换一次配置的需求。
    • 上游 atomic KMS 成熟后,ADF 被放弃。
    • Android 7.0 推出 HWC2;8.0 的 Treble 把 HAL 和框架解耦。之后高通、联发科、三星等厂商陆续把显示驱动迁到 DRM/KMS。
  • 第三次交汇:ION 换成 dma-buf heaps。 Android 12 配合 GKI 通用内核,弃用 ION,改用上游的 dma-buf heaps。之后 Android 13 把 HWC 接口改成 AIDL 的 composer3。
阶段时间当时的问题引入的东西解决了什么
能上屏2008~2010(1.x~2.x)尽快把画面显示出来SurfaceFlinger 用 GLES 合成;fbdev 上屏;各厂商自己的显存分配器(pmem 等)能显示,但全靠 GPU 合成,耗电;分配器互不兼容
省电和流畅2011~2013(3.0~4.4)GPU 合成耗电,画面卡顿、撕裂HWC 1.x;ION;VSYNC 和三缓冲;自家 sync 框架视频等场景不用 GPU 合成;buffer 统一分配;60fps 流畅
另起炉灶又放弃2013 前后KMS 没有原子提交ADF很少有厂商采用,上游 atomic KMS 成熟后放弃
接口规范化2016~2019(7.0~10)HWC 1.x 语义含糊;HAL 和框架绑死,升级困难HWC2;Treble;drm_hwcomposer;厂商迁到 DRM/KMSHWC 的“试分配再提交”直接对应 atomic 的 TEST_ONLY 和提交
回归上游2020 至今(11~)各厂商的内核分叉太多,没法统一升级GKI;dma-buf heaps;AIDL 的 composer3 和 gralloc显示驱动就是上游形态的 DRM/KMS 驱动,Android 和 Linux 共用

对我们的意义:Android 上的显示驱动已经能直接给 Linux 用

Section titled “对我们的意义:Android 上的显示驱动已经能直接给 Linux 用”

演进的终点对 SoC 厂商很有利:

  • 显示驱动不用为 Linux 重写。 只要现在的驱动是标准的 atomic KMS 驱动,HWC 能用的,Aquamarine 基本也能用。补齐的主要是 HWC 曾经替驱动兜底的部分,比如 vblank 和 TE 信号、syncobj 声明。
  • buffer 和同步机制两边一样。 dma-buf 和 sync_file 本来就是内核标准件,换系统不用改。
  • 唯一没并回上游的是 GPU 驱动。 Arm 的 kbase 至今是独立驱动,不是 DRM 驱动。它对应的上游驱动是 panthor,等 panthor 支持 G2 后,GPU 这一层也能和上游完全一致。