SurfaceFlinger
SurfaceFlinger 接受来自多个源的数据缓冲区,将它们组合起来,然后将它们发送到显示设备。以前,这个过程是通过软件位阻塞传输到硬件帧缓冲区(例如/dev/graphics/fb0)来实现的,但那些日子已经一去不复返了。
当应用程序进入前台时,WindowManager 服务向SurfaceFlinger 请求绘图Surface。 SurfaceFlinger创建一个Layer,其主要组件是BufferQueue,SurfaceFlinger是BufferQueue的消费者。生产者端的Binder对象通过WindowManager传递给应用程序,然后应用程序就可以开始直接向SurfaceFlinger发送帧。
注意:虽然本节使用SurfaceFlinger 术语,但WindowManager 使用术语“窗口”(而不是“层”).并且“层”用于表示其他含义。 (有人认为SurfaceFlinger 实际上应该被称为LayerFlinger。)
大多数应用程序通常在屏幕上有三层:屏幕顶部的状态栏、底部或侧面的导航栏以及应用程序的界面。某些应用程序将具有更多或更少的层(例如,默认主屏幕应用程序具有单独的壁纸层,而全屏游戏可能会隐藏状态栏)。每个层都可以单独更新。状态栏和导航栏是由系统进程渲染的,而应用层是由应用程序渲染的,两者之间没有协调。
设备显示屏的刷新速度在手机和平板电脑上通常为每秒60 帧。刷新时如果更新显示内容,会出现撕裂现象;因此,请确保仅在周期之间更新内容。当可以安全更新内容时,系统会接收来自显示设备的信号。由于历史原因,我们将此信号称为VSYNC 信号。
刷新率可能会随时间而变化,例如,某些移动设备的刷新率范围为58 fps 到62 fps,具体取决于当前条件。对于HDMI 连接的电视,理论上刷新率可以降至24 Hz 或48 Hz 以匹配视频。由于屏幕每个刷新周期只能更新一次,因此以200 fps 的刷新率将缓冲区提交到显示设备只是浪费时间,因为大多数帧永远不会被看到。 SurfaceFlinger 在应用提交缓冲区时不会执行操作,而是在显示设备准备好接收新缓冲区时唤醒。
当VSYNC 信号到达时,SurfaceFlinger 会遍历其图层列表,寻找新的缓冲区。如果找到新的缓冲区,则获取它;否则,它继续使用先前获取的缓冲区。 SurfaceFlinger 总是需要显示一些内容,因此它会保留一个缓冲区。如果某个层上没有提交任何缓冲区,则该层将被忽略。
SurfaceFlinger 收集可见层的所有缓冲区后,它会询问Hardware Composer 应该如何组合。
Hardware Composer
Hardware Composer HAL (HWC) 是在Android 3.0 中引入的,并且已经发展了多年。它主要用于确定用可用硬件合成缓冲区的最有效方法。作为HAL,其实现是特定于设备的,通常由显示设备硬件原始设备制造商(OEM) 完成。
当考虑叠加平面时,这种方法的好处是显而易见的。其目的是在显示硬件(而不是GPU)中将多个缓冲区组合在一起。例如,想象一下处于纵向模式的普通Android 手机,状态栏位于顶部,导航栏位于底部,应用程序内容位于其他位置。每层的内容位于单独的缓冲区中。您可以使用以下任一方法处理合成:
将应用程序内容渲染到暂存缓冲区中,然后在其顶部渲染状态栏,在其顶部渲染导航栏,最后将暂存缓冲区传递到显示硬件。
将所有三个缓冲区发送到显示硬件,并告诉它从屏幕不同部分的不同缓冲区读取数据。
后一种方法可以显着提高效率。
显示处理器的功能差异很大。叠加的数量(图层是否可以旋转或混合)以及定位和叠加的限制很难通过API 表达。 HWC 试图通过一系列决定来适应这种多样性:
SurfaceFlinger 向HWC 提供完整的层列表,并询问“您想用这些层做什么?”
HWC 通过将每一层标记为覆盖层或GLES 组合来做出响应。
SurfaceFlinger 处理所有GLES 组合,将输出缓冲区传递给HWC,并让HWC 处理其余部分。
由于硬件供应商可以定制决策代码,因此可以在每个设备上实现最佳性能。
当屏幕上没有任何变化时,覆盖平面的效率可能低于GL 合成。当覆盖内容具有透明像素并且覆盖混合在一起时尤其如此。在这种情况下,HWC 可以选择请求部分或所有层的GLES 合成并保留合成缓冲区。如果SurfaceFlinger 返回组成同一组缓冲区的请求,HWC 可以继续显示之前组成的暂存缓冲区。这可以延长闲置设备的电池寿命。
运行Android 4.4 或更高版本的设备通常支持4 个覆盖平面。尝试合成比堆叠层更多的层将导致系统对其中某些层使用GLES 组合,这意味着应用程序使用的层数会对功耗和性能产生重大影响。
虚拟显示设备
SurfaceFlinger 支持主显示设备(即手机或平板电脑内置的显示器)、外部显示设备(例如通过HDMI 连接的电视)以及一个或多个虚拟显示器,使合成输出可用系统。显示设备。虚拟显示设备可用于记录屏幕或通过网络发送屏幕。
虚拟显示设备可以与主显示设备共享相同的层集(层堆栈),也可以拥有自己的层集。虚拟显示设备没有VSYNC,因此主显示设备的VSYNC用于触发所有显示器的合成。
在旧版本的Android 中,虚拟显示设备始终通过GLES 进行合成,而Hardware Composer 仅管理主显示设备的合成。在Android 4.4中,Hardware Composer可以参与虚拟显示合成。
正如您所期望的,为虚拟显示设备生成的帧将写入BufferQueue。
案例研究:screenrecord
screenrecord 命令允许您将屏幕上显示的所有内容以.mp4 文件的形式记录到磁盘上。为此,我们必须从SurfaceFlinger 接收合成帧,将它们写入视频编码器,然后将编码后的视频数据写入文件。视频编解码器由单独的进程(媒体服务器)管理,因此我们必须在系统中移动大量图形缓冲区。为了使其更具挑战性,我们尝试以全分辨率以60 fps 录制视频。高效完成此操作的关键是BufferQueue。
MediaCodec 类允许应用程序在缓冲区中或通过Surface 以原始字节形式提供数据。当screenrecord 请求访问视频编码器时,mediaserver 创建一个BufferQueue,将自身连接到消费者端,然后将生产者端作为Surface 传递回screenrecord。
然后,screenrecord 命令要求SurfaceFlinger 创建一个虚拟显示设备,该设备镜像主显示设备(即,它具有完全相同的层),并指示其将输出从媒体服务器发送到Surface。在这种情况下,SurfaceFlinger 是缓冲区的生产者,而不是消费者。
配置完成后,screenrecord 会等待显示编码数据。当应用程序绘制时,其缓冲区会转到SurfaceFlinger,后者将它们合成为单个缓冲区并将它们直接发送到媒体服务器中的视频编码器。屏幕录制过程甚至看不到全帧。在内部,mediaserver 有自己的移动缓冲区的方式,它也通过句柄传递数据,从而最大限度地减少开销。
案例研究:模拟辅助显示设备
WindowManager 可以要求SurfaceFlinger 创建一个可见层,并将SurfaceFlinger 作为其BufferQueue 使用者。您还可以要求SurfaceFlinger 创建虚拟显示设备,同样使用SurfaceFlinger 作为其BufferQueue 生产者。如果我连接它们并配置渲染到可见层的虚拟显示设备,会发生什么?
创建一个闭环,其中复合屏幕显示在窗口中。该窗口现在是合成输出的一部分,因此在下次刷新时,该窗口中的合成图像也会显示窗口内容(并且循环将永远持续)。要查看此过程的实际效果,请在“设置”中启用“开发人员选项”,选择“模拟辅助显示设备”,然后启用一个窗口。作为奖励,您可以使用screenrecord 捕获支持显示的设备的操作,然后逐帧播放它们。
OK,关于深入解析现代架构设计:核心技术与实践案例和的内容到此结束了,希望对大家有所帮助。
【深入解析现代架构设计:核心技术与实践案例】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
终于来了!一直在等架构2的更新呢。
有7位网友表示赞同!
架构2 会有什么新的功能?我好好奇啊。
有8位网友表示赞同!
看名字就知道肯定很先进了,期待着它的发布!
有17位网友表示赞同!
以前架构1就很优秀了,现在架构2肯定更加厉害吧!
有10位网友表示赞同!
这篇文章是关于新版本的架构吗?
有12位网友表示赞同!
希望能详细介绍一下架构2的区别和优势。
有14位网友表示赞同!
架构2 是针对谁设计的?有什么适用场景呢?
有13位网友表示赞同!
希望架构2能解决之前版本的一些问题。
有14位网友表示赞同!
学习一下新的架构,提升自己!
有8位网友表示赞同!
期待架构2能够带来更大的创新!
有15位网友表示赞同!
对于新手来说,如何理解和使用架构2呢?
有5位网友表示赞同!
有相关的教程资料吗?希望能方便地学习。
有20位网友表示赞同!
有没有官方的文档和说明?
有14位网友表示赞同!
分享一下你的看法和期待吧!
有7位网友表示赞同!
这个标题听起来很专业,很有深度哦。
有12位网友表示赞同!
架构2 会对行业有什么样的影响呢?
有8位网友表示赞同!
我相信架构2会成为未来的发展趋势!
有16位网友表示赞同!
希望能看到更多关于架构2的探讨和分析。
有6位网友表示赞同!
期待了解更多精彩的内容!
有15位网友表示赞同!
这个标题真是太吸引人了!
有7位网友表示赞同!