本系列的文章,可以让你明白,一个View最终是如何显示到屏幕上的,从应用层到硬件抽象层。对分析app的卡顿,掉帧等 有很大帮助。
应用层可通过两种方式将图像绘制到屏幕上:使用 Canvas 或 OpenGL :
下面这张官方图片,提现了 图像流 从 Image stream producers 到Surface,再被 Image stream consumers 中的SurfaceFlinger(其中也有OpenGl ES的一些工作)消费掉,再到硬件抽象层,最后显示到屏幕上
Activity 也是需要创建Surface的, Activity显示流程为:
一般app而言,屏幕会有三个layer:屏幕顶端的status bar,屏幕下面的navigation bar,还有就是app的UI部分。
app的layer可能多余或者少于3个,例如对全屏显示的app就没有status bar。
status bar和navigation bar是由系统进行去render。而app的UI部分对应的layer 是由它自己去处理(通知SurfaceFlinger处理),最后需要把这些layer合成 。
无论开发者使用Canvas 或 OpenGLI,一切内容都会渲染到 Surface 。在 Android 平台上创建的每个窗口都由 Surface 提供支持。
SurfaceFlinger 会把系统中所有应用程序的最终的“绘图结果”进行“混合”,然后统一显示到物理屏幕上,
图像流生产者与图像流消费者 的数据传递就是通过 BufferQueue ,里面有很多的GraphicBuffer
这是生产者消费者模型。一旦生产者 有新数据,就会通知 SurfaceFlinger 进行消费,最后显示到屏幕
生产者和消费者可能是在不同的进程,它们的通信不是用Binder,为了高效传输大块数据,使用匿名共享内存,BufferQueue 不会复制缓冲区内容;通过句柄进行传递。
下图是上图的细化
接下来具体说明客户端(producer)和服务端SurfaceFlinger(consumer)工作的模式:首先这里的buffer是共享缓冲区,故肯定会涉及到互斥锁,所以buffer的状态也会有多种,一般的buffer大致会经过FREE->DEQUEUED->QUEUED->ACQUIRED->FREE这个流程,如下图:
图像生产者 例如:相机 HAL 或 OpenGL ES 游戏生成的相机预览。
图像消费者 例如:SurfaceFlinger 或显示 OpenGL ES 流的另一个应用,如显示相机取景器的相机应用。
BufferQueue 通常用于渲染到 Surface ,并且与 GL 消费者及其他任务一起消耗内容。BufferQueue 可以在三种不同的模式下运行:
Android 平台图形处理 API 的标准:
OpenGL ES 是 Android 绘图 API ,但 OpenGL ES 是平台通用的,与系统无关的,在特定设备上使用需要一个中间层做适配, Android 中这个中间层就是 EGL 。
Linux 抽象出 FrameBuffer 这个设备来供用户态进程实现直接写屏。FrameBuffer 机制模仿显卡的功能,是显卡硬件的抽象,可以通过 FrameBuffer 的读写直接对显存进行操作。
用户可以将 FrameBuffer 看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。
用户不必关心物理显存的位置、换页机制等等具体细节,这些都是由 FrameBuffer 设备驱动来完成的。但 FrameBuffer 本身不具备任何运算数据的能力。
CPU 将运算后的结果放到FrameBuffer,就会显示处理,中间不会对数据做处理。应用程序也可以直接读写FrameBuffer,尽管 FrameBuffer 需要真正的显卡驱动的支持,但所有显示任务都有 CPU 完成,因此 CPU 负担很重。
帧缓存可以在系统存储器(内存)的任意位置,视频控制器通过访问帧缓存来刷新屏幕。
帧缓存也叫刷新缓存 FrameBuffer 或 RefreshBuffer ,这里的帧 Frame 是指整个屏幕范围。帧缓存有个地址,是在内存里。我们通过不停的向 FrameBuffer 中写入数据,显示控制器就自动的从 FrameBuffer 中取数据并显示出来。全部的图形都共享内存中同一个帧缓存。
FrameBuffer 帧缓冲实际上包括两个不同的方面:
FrameBuffer 就是一个存储图形/图像帧数据的缓冲。Linux 内核提供了统一的 Framebuffer 显示驱动,设备节点 /dev/graphics/fb* 或者 /dev/fb* ,以 fb0 表示第一个 Monitor ,这个虚拟设备将不同硬件厂商实现的真实设备统一在一个框架下,这样应用层就可以通过标准的接口进行图形/图像的输入和输出了:
Gralloc 的含义为是 Graphics Alloc 图形分配 。Android 系统在硬件抽象层中提供了一个 Gralloc 模块,封装了对 Framebuffer 的所有访问操作。
Gralloc 模块符合 Android 标准的 HAL 架构设计;它分为 fb 和 gralloc 两个设备:前者负责打开内核中的 Framebuffer 、初始化配置,以及提供 post, setSwapInterval 等操作;后者则管理帧缓冲区的分配和释放。上层只能通过 Gralloc 访问帧缓冲区,这样一来就实现了有序的封装保护。
Gralloc 分配器返回的句柄可以通过 Binder 在进程之间传递。
HWC(hwcomposer)是Android中进行窗口(Layer)合成和显示的HAL层模块,其实现是特定于设备的,而且通常由显示设备制造商 (OEM)完成,为SurfaceFlinger服务提供硬件支持。
SurfaceFlinger可以使用OpenGL ES合成Layer,这需要占用并消耗GPU资源。
大多数GPU都没有针对图层合成进行优化,当SurfaceFlinger通过GPU合成图层时,应用程序无法使用GPU进行自己的渲染。而HWC通过硬件设备进行图层合成,可以减轻GPU的合成压力。
显示设备的能力千差万别,很难直接用API表示硬件设备支持合成的Layer数量,Layer是否可以进行旋转和混合模式操作,以及对图层定位和硬件合成的限制等。因此HWC描述上述信息的流程是这样的:
至此,本系列涉及到的内容主要内容,都大概描述了一下,还有一些流程中涉及到的VSync,WMS等,这些不是很影响整体的逻辑,再后面的文章再具体分析。
原文地址:https://xuexuan.blog.csdn.net/article/details/108870372
最后欢迎大家加入 音视频开发进阶 知识星球 ,这里有知识干货、编程答疑、开发教程,还有很多精彩分享。
更多内容可以在星球菜单中找到,随着时间推移,干货也会越来越多!!!