从零开始给 Surface 实现 SurfaceSyncGroup
背景
我的上一篇文章讲到了给 Surface
实现帧同步,作为实现帧同步的重要手段,在做动画需求,特别是跨进程同步渲染的需求中发挥了重要的作用。但还有另一种跨进程渲染的方案,在 Android13 被提了出来,这便是 SurfaceSyncGroup
。SurfaceSyncGroup
是用来替代 SurfaceSyncer
的方案的,SurfaceSyncer
我没用过(Android13 发布的时候我刚工作一年),所以就不提了,不过值得注意的是,这个用来帧同步的 SurfaceSyncGroup
居然是作为开放 API
发布的,难得见到谷歌慷慨了一回啊,之前图形绘制相关的 API
,不管是 BLAST
相关还是 SurfaceSyncer
都是标明了 hide 接口的。
所以我为什么老是需要用到帧同步这些东西呢,因为我在去年年末的时候接手了桌面的窗口动画业务,特别是在后续的需求中引入多个 Surface
动画之后,有些场景并不能单纯依靠事务。比如绘制的同步就不能依靠我上一篇文章中的那种方法,这就涉及到 Surface
绘制的原理了,绘制是一种隐式的事务,在绘制操作从主线程转移到 RenderThread
上帧渲染完成之后,缓冲区就会挂到一个 Transaction
上,然后这个 Transaction
被发送到 SurfaceFlinger
去进行合成。这点可以通过 Winscope
来验证,在 Windscope
的 Transcation
一栏,是可以找到带有 Buffer
的 Transaction
的。
关于 SurfaceSyncGroup
的原理,网上一搜讲解很多,我这里就不详细展开了,简单来说就是通过一个根 group
,来管理所有的子 group
。对于这个根 group
,如果是本地进程就由本地进程管理,如果是跨进程则通过 WMS
来管理。每个子 group
在绘制完成之后需要调用 markSyncReady
来通知根 group
,然后根 group
会检查是否所有的子 group
已经全部准备好,如果全部准备好了,就调用 Transaction#apply
来应用事务。那怎么做到同步帧缓冲的呢?想起我上面说的了吗,绘制也是一种隐式的事务,最终也是要转为事务来应用的,只不过对于开发者来说是个黑箱,无感知而已。