Android Graphics

一、Graphics介绍

无论开发者使用哪种接口,所有的内容都会被渲染到“Surface”之上。surface表示一个buffer queue的生产者端,buffer queue通常被SurfaceFlinger消费。Android平台上被创建的每一个窗口都会有一个Surface对应。所有完场渲染的可见Surface都会被SurfaceFlinger合成到display上去显示。

下图是Graphics的核心组件:

上图是16年官方给出的,随着几年的更新也引入了一些新的模块,支持了新的图形库-Vulkan,Gralloc和BufferQueue也做了相应的支持,我们可以继续细化下整体流程,全景图如下:

图像流生产者(Image Steam Producers)

一个图像流生产者表示可以产生图像buffer的任何组件。例如包括Open ES,Canvas 2D 和mediaserver vide decoders。

图像流消费者(Image Stream Consumers)

大部分情况下,通常的图像流消费者是SurfaceFlinger,SurfaceFlinger是一个系统服务用于消费当前的可见surface并且将他们合成到display,前提是使用Window Manager提供的参数。SurfaceFlinger是唯一可以修改显示内容的服务。SurfaceFlinger使用OpenGL和硬件合成器来来合成一组surface。

其他的OpenGL ES应用也可以消耗图像流,例如Camera app消耗了camera 预览图像流。非GL应用也可以成为消费者,例如ImageReader 类。

窗口管理器(Window Manager)

控制窗口的Android系统服务,窗口是view的容器。一个窗口总是对应一个surface。这个服务监督窗口的生命周期,输入和焦点事件,屏幕方向,透明度,动画,位置,形变,z-order等等。窗口管理器发送所有的window元数据到SurfaceFlinger,从而SurfaceFlinger可以使用这些数据来合成surface。

硬件合成器(Hardware Composer)

显示子系统的硬件抽象。SurfaceFlinger可以授权一些特定的合成工作到硬件合成器,从而降低OpenGL和GPU的工作负担。SurfaceFlinger仅仅是另一个OpenGL ES客户端。所以例如当SurfaceFlinger积极地将一个或多个buffer合成到第三个时,它使用的是OpenGL ES。这使得在合成时比用GPU进行全部的计算功耗更低。

硬件合成器抽象层负责一半的工作并且是Android图行渲染的中心点。硬件合成器需要支持event,例如VSYNC(另一个时间是HDMI的热插拔事件支持)。

颜色编码

RGB和YUV是两种常用的颜色编码方式,它们在图像和视频处理中起着重要的作用。它们的主要区别在于颜色表示方式和用途。

RGB是红绿蓝(Red, Green, Blue)的缩写,它是一种加法混色模式。在RGB中,每个像素的颜色由红、绿、蓝三个分量的强度值来表示,每个分量的取值范围是0到255。通过调整这三个分量的强度值,可以得到不同的颜色。RGB编码适用于显示器、摄像头等设备,因为它们使用红、绿、蓝三种颜色的光来显示图像。

YUV是亮度(Luminance)和色度(Chrominance)的缩写,它是一种亮度和色度分离的编码方式。在YUV中,亮度分量Y表示图像的明亮程度,而色度分量U和V表示颜色信息。亮度分量Y的取值范围是0到255,而色度分量U和V的取值范围是-128到127。YUV编码适用于视频压缩和传输,因为人眼对亮度更加敏感,而对色度的感知相对较低。通过将图像的颜色信息与亮度信息分离,可以实现更高效的压缩和传输。

由于RGB和YUV表示颜色的方式不同,所以它们之间需要进行转换。转换的过程可以通过一系列的数学运算来实现。具体的转换公式可以参考相关资料或者算法实现。

视频编码标准

H.264,也称为AVC(Advanced Video Coding),是一种广泛使用的视频编码标准。它采用了先进的压缩算法,可以在保持较高视频质量的同时,显著减小视频文件的大小。H.264广泛应用于各种领域,包括互联网视频、蓝光光盘、视频会议等。

H.265,也称为HEVC(High Efficiency Video Coding),是H.264的后继者。H.265在相同视频质量下,可以将视频文件大小再次减小约50%。这使得H.265在带宽受限或存储资源有限的环境下具有更好的性能。H.265适用于4K和8K超高清视频、流媒体服务等。

H.266,也称为VVC(Versatile Video Coding),是最新的视频编码标准。H.266相比于H.265,可以将视频文件大小再次减小约50%,同时保持相同的视频质量。这使得H.266在移动设备、网络传输和存储资源有限的场景下具有更高的效率。

H.264、H.265、H.266的视频都是经过压缩的,经过解码可以生成RGB视频或YUV视频,这两种格式的视频是非压缩格式的。

视频传输标准

BT.656是一种视频传输标准,也被称为ITU-R BT.656或CCIR 656。它定义了一种将数字视频数据传输到模拟视频信号的方法。BT.656标准主要用于将数字视频数据从摄像头、视频采集卡或其他数字视频源传输到显示设备,如电视机或监视器。

BT.656标准规定了视频数据的时序、帧格式和同步信号等方面的细节。它使用8位或10位的并行数据接口来传输视频数据,并通过同步信号来确保数据的正确对齐和解析。BT.656还定义了垂直同步信号和水平同步信号,用于确定视频帧的开始和结束位置。

BT.656标准支持多种视频格式,包括标清(SD)和高清(HD)视频。它可以传输各种视频信号,如PAL、NTSC和SECAM等。此外,BT.656还定义了音频数据的传输方式,可以将音频数据与视频数据一起传输。

BT.656标准中定义了两种常见的数据格式:4:2:2和4:2:0。这两种格式都是基于YUV颜色空间的,其中Y表示亮度分量,U和V表示色度分量。RGB格式则是基于红、绿、蓝三个颜色通道的。

视频编码标准和视频传输标准组合

BT.656 H.264是一种视频编码标准和传输接口标准的组合。BT.656是一种视频传输接口标准,定义了基于时序同步的并行接口,用于将数字视频数据从摄像头或其他视频源传输到显示设备或其他处理设备。H.264是一种视频编码标准,也被称为AVC(Advanced Video Coding),它可以将视频数据进行高效压缩,以便在有限的带宽和存储资源下传输和存储。

BT.656定义了视频数据的传输格式和时序,包括行同步信号、场同步信号、像素时钟等。H.264定义了视频数据的编码格式和压缩算法,包括帧内预测、帧间预测、变换编码等技术,以实现更高的压缩比和更好的视频质量。

通过将BT.656和H.264结合起来使用,可以实现从摄像头或其他视频源采集到的视频数据的实时传输和压缩。这种组合广泛应用于视频监控、视频会议、数字电视等领域。

视频接口标准

GMSL(Gigabit Multimedia Serial Link)是一种高速串行数据传输接口,主要用于汽车电子系统中的视频和音频数据传输。它采用差分信号传输,支持高达6Gbps的数据传输速率,具有抗干扰能力强和传输距离远的特点。

GVIF(Gigabit Video Interface)是一种高速视频接口标准,主要用于连接车载摄像头和车载显示屏之间的数据传输。它采用差分信号传输,具有高带宽和抗干扰能力强的特点。

MIPI(Mobile Industry Processor Interface)是一种移动行业处理器接口标准,主要用于连接移动设备中的摄像头、显示器和其他外设。它采用串行信号传输,具有低功耗和高带宽的特点,适用于移动设备中的视频和图像传输。

HDMI(High-Definition Multimedia Interface)是一种高清晰度多媒体接口标准,主要用于连接高清显示设备(如电视、投影仪等)和多媒体设备(如电脑、DVD播放器等)。它支持高清视频和多声道音频传输,具有数字信号传输、高质量图像和音频传输的特点。

DVI(Digital Visual Interface)是一种数字视频接口标准,主要用于连接计算机和显示设备之间的数据传输。它支持高质量图像传输,可以传输数字信号或模拟信号,具有较高的图像质量和抗干扰能力。

VGA(Video Graphics Array)是一种模拟视频接口标准,主要用于连接计算机和显示设备之间的数据传输。它是最早的视频接口标准之一,支持较低的分辨率和色彩深度,逐渐被数字接口标准所替代。

Window Manager

用于管理Window.Window是个抽象类,表示一个窗口,其实现是PhoneWIndow。 WindowManager 会监督生命周期、输入和聚焦事件、屏幕方向、转换、动画、位置、变形、Z 轴顺序以及窗口的许多其他方面。当app通过WindowManager创建一个Window时,WindowManagerService会为每一个Window创建一个Surface,并将各种(包括屏幕信息,z-order等)信息发送给SurfaceFlinger。

Surface

Surface 表示 APP 进程的一个窗口,承载了窗口的图形数据与SurfaceFlinger侧的Layer相对应 。从App侧来看不管是 Canvas , OpenGL ES还是Vulkan最终渲染到的目标都是 Surface ,现在比较流行的跨平台UI框架 Flutter 在 Android 平台上也是直接渲染到 Surface 。

一个Activity是一个Surface、一个Dialog也是一个Surface。

Gralloc

图形内存分配器,用于分配图像生产者请求的内存。

含义是 Graphics Alloc 图形分配, 用于图形生产时请求分配内存.Android 系统在硬件抽象层中提供了一个 Gralloc 模块,封装了对 Framebuffer 的所有访问操作。

Gralloc 模块符合 Android 标准的 HAL 架构设计;它分为 fb 和 gralloc 两个设备:前者负责打开内核中的 Framebuffer 、初始化配置,以及提供 post, setSwapInterval 等操作;后者则管理帧缓冲区的分配和释放。

BufferQueue

BufferQueue在Android图形组件之间起到粘合作用。这是一对queue,用于实现从生产者到消费者的恒定循环。一旦生产者交出buffer,SurfaceFlinger就承担起将所有东西合成到display的责任。

SurfaceFlinger

Android 系统服务,会随着init进程执行init.rc而创建该服务。负责合成所有 Surface 提供的图形数据,然后送显到屏幕。SurfaceFlinger 既是上层应用的消费者,又是 Display 的生产者。功能如下:

分配图形缓冲区

合成Surface

管理 VSYNC 事件

为了更好的理解SurfaceFlinger这个服务的工作内容,以及他是如何做到一个承上启下的作用,我们通过下面的这个界面分析:

我们可以先这样理解上面这幅图,上层每一个界面,其实都对应SufaceFlinger里的一个Surface对象,上层将自己的内容绘制在对应的Surface内,接着,SufaceFlinger需要将所有上层对应的Surface内的图形进行合成,具体看下图:

SurfaceFlinger就是将多个Surface里的内容进行合成,最后提交到屏幕的后缓冲区,等待屏幕的下一个垂直同步信号的到来,再显示到屏幕上。

我们会发现SufaceFlinger通过屏幕后缓冲区与屏幕建立联系。同时通过Surface与上层建立联系。从而起到一个承上启下的作用,是Android图形系统结构中的关键组成部分。

Canvas

Canvas 是一个2D图形 API ,是 Android View 树实际的渲染者。Canvas 又可分为Skia 软件绘制和 hwui 硬件加速绘制。

OpenGL

传统的图形API,规范了图形接口,Opengl ES是一个专用于嵌入式设备的OpenGL,但Opengl本身只提供接口和规范,具体的需要各平台提供接口层去适配自己的窗口体系,比如Android平台的EGL。生态好,适用广泛。

Kanzi

Kanzi是一个开源的汽车人机交互(HMI)软件平台,旨在为汽车制造商和供应商提供一个灵活、可定制的用户界面解决方案。它提供了丰富的功能和工具,用于设计和开发车载界面,包括仪表盘、中控屏幕、语音控制和手势识别等。

Kanzi平台基于C++开发,支持跨多个操作系统和硬件平台,如Linux、Android和QNX等。它提供了一套强大的工具和库,用于创建高度可视化的界面,并支持多种输入方式和交互方式。开发人员可以使用Kanzi Studio进行界面设计和布局,通过Kanzi Engine进行界面渲染和交互逻辑的实现。

Kanzi还提供了丰富的图形效果和动画库,以及预定义的组件和模板,使开发人员能够快速构建出具有吸引力和易用性的车载界面。此外,Kanzi还支持多语言和多地区的本地化,以满足不同市场和用户的需求。

Android系统中Kanzi使用的是OpenGL ES。

Unity

Unity是一款跨平台的游戏开发引擎,它可以用于开发2D和3D游戏、虚拟现实(VR)和增强现实(AR)应用程序。Unity提供了一个可视化的开发环境,使开发者可以轻松创建游戏场景、添加游戏对象、设置物理效果、编写脚本等。以下是Unity的一些特点和功能:

  1. 跨平台支持:Unity可以在多个平台上运行,包括Windows、Mac、iOS、Android等。

  2. 强大的图形渲染能力:Unity支持高质量的图形渲染,包括实时光照、阴影、粒子效果等。

  3. 内置的物理引擎:Unity内置了物理引擎,可以模拟真实世界中的物理效果,如重力、碰撞等。

  4. 可视化编辑器:Unity提供了一个可视化的编辑器界面,使开发者可以直观地编辑场景、调整参数等。

  5. 脚本编程:Unity使用C#作为主要的脚本编程语言,开发者可以使用C#编写游戏逻辑和交互。

  6. 多种资源支持:Unity支持导入和使用各种资源文件,如模型、纹理、音频等。

  7. 社区支持和插件生态系统:Unity拥有庞大的开发者社区和丰富的插件生态系统,开发者可以从中获取支持和资源。

  8. 实时预览和调试:Unity提供实时预览功能,开发者可以在编辑器中即时查看游戏效果,并进行调试。

  9. 支持多人协作:Unity支持多人协作开发,多个开发者可以同时编辑同一个项目。

  10. 发布和分发:Unity可以将游戏打包发布到各个平台,并支持应用商店的分发。

Android系统中Unity使用的是OpenGL ES。

FrameBuffer

Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。FrameBuffer是显卡硬件的抽象,可以通过FrameBuffer的读写直接对显存进行操作。

FrameBuffer本身不具备任何运算数据的能力,CPU将运算后的结果放到FrameBuffer,就会显示处理,中间不会对数据做处理。

Linux内核提供了统一的Framebuffer显示驱动,节点为/dev/graphics/fb* 或者 /dev/fb* ,以fb0表示第一个 Monitor,这个虚拟设备将不同硬件厂商实现的真实设备统一在一个框架下,这样应用层就可以通过标准的接口进行图形/图像的输入和输出。

/dev/fb是Linux系统中的帧缓冲设备,它用于在图形显示中进行像素级别的操作。根据提供的引用内容,帧缓冲设备是一个标准字符设备,它并没有内置的缓存机制。每次对/dev/fb设备的读写操作都会直接访问显存,而不会经过缓存。

因此,对于/dev/fb设备的读写操作是实时的,不会有缓存的延迟。这意味着,当你对/dev/fb设备进行读取时,你将立即获得当前屏幕上的像素数据,而当你对/dev/fb设备进行写入时,你将立即将像素数据写入到屏幕上。

总结起来,/dev/fb设备没有内置的缓存机制,它提供了实时的像素级别的读写操作。

Hardware Composer(硬件混合渲染器)

Android中进行窗口(Layer)合成和显示的HAL层模块,显示子系统的硬件抽象实现。其内部实现是基于特定设备的,通常由屏幕硬件设备制造商 (OEM) 完成。主要用于确定合成缓冲区的最有效方式,SurfaceFlinger 在收集可见层的所有缓冲区后,便会询问 HWC 应如何进行合成。可分为Client合成和Device合成。SurfaceFlinger 可以将某些合成工作委托给 Hardware Composer,以分担 GPU 上的工作量。

同步框架 (Synchronization framework)

因为Android graphics没有明确的并行性,vendor长期以来在自己的驱动中实施隐式的同步策略。使用Android Graphics同步框架后这将不再需要。

同步框架明确地描述了不同异步操作之间的依赖关系。此框架提供了一组简单的API,让组件在buffer被释放后发出信号。同时还允许从kernel到userspace或 userspace的进程之间传递同步原语。

举个例子,应用程序可以将需要执行的工作放在GPU中排队,然后GPU开始绘制图像。尽管图像还没有绘制到内存中,buffer的指针仍然可以与一个fence被传到窗口合成器,fence可以表示GPU什么时候完成工作。然后窗口合成器可以提前开始工作,并将工作移交给display controller。一旦GPU完成工作,display controller可以立马进行图像的显示。

同步框架还可以允许实现着在自己的硬件组件中使用同步资源。最后,此框架提供Graphics管线的可视性来帮助调试。

Vsync

在图形和图像显示中,VSYNC是一个非常重要的概念,它是指垂直同步信号,用于控制显示器刷新率和显示时序。在Android系统中,VSYNC机制被广泛应用于控制屏幕显示和动画渲染,以提高显示效果和性能。

在Android中,每台设备都有一个硬件VSYNC信号发生器,用于生成恒定的刷新率信号。通常情况下这个信号的刷新率为60Hz或90Hz,Android显示框架可以根据这个信号来调整自己的显示和渲染速度。在SurfaceFlinger的生成者消费者模型中,当硬件VSYNC信号发生时,SurfaceFlinger会开始读取缓冲区中的数据,并将其显示在屏幕上。因此,如果Android显示框架在VSYNC前完成了数据处理和绘制,则可以实现零延迟的图像或动画渲染。

VSYNC机制的主要优点是可以避免在图像渲染过程中出现屏幕撕裂和卡顿现象,同时,使用硬件信号,可以使图形和图像处理与显示保持同步,提高显示效果和渲染性能。

由于图像绘制和屏幕读取 使用的是同个buffer,所以屏幕刷新时可能读取到的是不完整的一帧画面。双缓存,让绘制和显示器拥有各自的buffer:GPU 始终将完成的一帧图像数据写入到 Back Buffer,而显示器使用 Frame Buffer,当屏幕刷新时,Frame Buffer 并不会发生变化,当Back buffer准备就绪后,它们才进行交换。

什么时候进行两个buffer的交换呢?

当扫描完一帧画面后,设备需要重新回到第一行以进入下一次的循环,此时有一段时间空隙,称为VerticalBlanking Interval(VBI)。那,这个时间点就是我们进行缓冲区交换的最佳时间。因为此时屏幕没有在刷新,也就避免了交换过程中出现 screen tearing的状况。

VSYNC 信号是由屏幕(显示设备)产生的,利用VBI时期出现的vertical sync pulse(垂直同步脉冲)来保证双缓冲在最佳时间点才进行交换。并且以 60fps 的固定频率发送给 Android 系统,Android 系统中的 SurfaceFlinger 接收发送的 VSYNC 信号。VSYNC 信号表明可对屏幕进行刷新而不会产生撕裂。另外,交换是指各自的内存地址,可以认为该操作是瞬间完成。

Android 4.4上又引入了Vsync虚拟化,通过DispSyncThread把Vsync虚拟化成Vsync-app和Vsync-sf,Vsync-app和Vsync-sf直接有固定的时机偏移,各自分别掌控着App和SurfaceFlinger的工作节奏,他们一前一后保持着绘制任务的流水节奏。

其中 app 和 sf 相对 hw_vsync_0 都有一个偏移,即 phase-app 和 phase-sf,如下图

Vsync Offset

Vsync Offset 我们指的是 VSYNC_APP 和 VSYNC_SF 之间有一个 Offset,即上图中 phase-sf - phase-app 的值,这个 Offset 是厂商可以配置的。如果 Offset 不为 0,那么意味着 App 和 SurfaceFlinger 主进程不是同时收到 Vsync 信号,而是间隔 Offset (通常在 0 - 16.6ms 之间)

目前大部分厂商都没有配置这个 Offset,所以 App 和 SurfaceFlinger 是同时收到 Vsync 信号的.

可以通过 Dumpsys SurfaceFlinger 来查看对应的值

Offset 为 0:(sf phase - app phase = 0)

Sync configuration: [using: EGL_ANDROID_native_fence_sync EGL_KHR_wait_sync]
DispSync configuration: 
 app phase 1000000 ns,              sf phase 1000000 ns 
 early app phase 1000000 ns,        early sf phase 1000000 ns 
 early app gl phase 1000000 ns,     early sf gl phase 1000000 ns 
 present offset 0 ns                      refresh 16666666 ns

Offset 不为 0 (SF phase - app phase = 4 ms)

Sync configuration: [using: EGL_ANDROID_native_fence_sync EGL_KHR_wait_sync]

VSYNC configuration:
         app phase:   2000000 ns	         SF phase:   6000000 ns
   early app phase:   2000000 ns	   early SF phase:   6000000 ns
GL early app phase:   2000000 ns	GL early SF phase:   6000000 ns
    present offset:         0 ns	     VSYNC period:  16666666 ns

下面以 Systrace 为例,来看 Offset 在 Systrace 中的表现:

首先说 Offset 为 0 的情况, 此时 App 和 SurfaceFlinger 是同时收到 Vsync 信号 , 其对应的 Systrace 图如下:

这个图上面也有讲解,这里就不再详细说明,大家只需要看到,App 渲染好的 Buffer,要等到下一个 Vsync-SF 来的时候才会被 SurfaceFlinger 拿去做合成,这个时间大概在 16.6 ms。这时候大家可能会想,如果 App 的 Buffer 渲染结束,Swap 到 BufferQueue 中 ,就触发 SurfaceFlinger 去做合成,那岂不是省了一些时间(0-16.6ms )?

答案是可行的,这也就引入了 Offset 机制,在这种情况下,App 先收到 Vsync 信号,进行一帧的渲染工作,然后过了 Offset 时间后,SurfaceFlinger 才收到 Vsync 信号开始合成,这时候如果 App 的 Buffer 已经 Ready 了,那么 SurfaceFlinger 这一次合成就可以包含 App 这一帧,用户也会早一点看到。

下图中,就是一个 Offset 为 4ms 的案例,App 收到 Vsync 4 ms 之后,SurfaceFlinger 才收到 Vsync 信号:

Offset 的一个比较难以确定的点就在与 Offset 的时间该如何设置,这也是众多厂商默认都不进行配置 Offset 的一个原因,其优缺点是动态的,与机型的性能和使用场景有很大的关系

如果 Offset 配置过短,那么可能 App 收到 Vsync-App 后还没有渲染完成,SurfaceFlinger 就收到 Vsync-SF 开始合成,那么此时如果 App 的 BufferQueue 中没有之前累积的 Buffer,那么 SurfaceFlinger 这次合成就不会有 App 的东西在里面,需要等到下一个 Vsync-SF 才能合成这次 App 的内容,时间相当于变成了 Vsync 周期+Offset,而不是我们期待的 Offset

如果 Offset 配置过长,就起不到作用了。

HW_VSYNC

HW_VSYNC 主要是利用最近的硬件 VSYNC 来做预测,最少要 3 个,最多是 32 个,实际上要用几个则不一定, DispSync 拿到 6 个 VSYNC 后就会计算出 SW_VSYNC,只要收到的 Present Fence 没有超过误差,硬件 VSYNC 就会关掉,不然会继续接收硬件 VSYNC 计算 SW_VSYNC 的值,直到误差小于 threshold.关于这一块的计算具体过程。

SurfaceFlinger 通过实现了 HWC2::ComposerCallback 接口,当 HW-VSYNC 到来的时候,SurfaceFlinger 将会收到回调并且发给 DispSync。DispSync 将会把这些 HW-VSYNC 的时间戳记录下来,当累计了足够的 HW-VSYNC 以后(目前是大于等于 6 个),就开始计算 SW-VSYNC 的偏移 mPeriod。计算出来的 mPeriod 将会用于 DispSyncThread 用来模拟 HW-VSYNC 的周期性起来并且通知对 VSYNC 感兴趣的 Listener,这些 Listener 包括 SurfaceFlinger 和所有需要渲染画面的 app。这些 Listener 通过 EventThread 以 Connection 的抽象形式注册到 EventThread。DispSyncThread 与 EventThread 通过 DispSyncSource 作为中间人进行连接。EventThread 在收到 SW-VSYNC 以后将会把通知所有感兴趣的 Connection,然后 SurfaceFlinger 开始合成,app 开始画帧。在收到足够多的 HW-VSYNC 并且在误差允许的范围内,将会关闭通过 EventControlThread 关闭 HW-VSYNC。

不使用HW_VSYNC:

使用 HW_VSYNC:

数据流

从 App 绘制到屏幕显示,分为下面几个阶段:

第一阶段:App 在收到 Vsync-App 的时候,在主线程进行 measure、layout、draw(构建 DisplayList , 里面包含 OpenGL 渲染需要的命令及数据) 。这里对应的 Systrace 中的主线程 doFrame 操作

第二阶段:CPU 将数据上传(共享或者拷贝)给 GPU, 这里 ARM 设备 内存一般是 GPU 和 CPU 共享内存。这里对应的 Systrace 中的渲染线程的 flush drawing commands 操作

第三阶段:通知 GPU 渲染,真机一般不会阻塞等待 GPU 渲染结束,CPU 通知结束后就返回继续执行其他任务,使用 Fence 机制辅助 GPU CPU 进行同步操作

第四 阶段:swapBuffers,并通知 SurfaceFlinger 图层合成。这里对应的 Systrace 中的渲染线程的 eglSwapBuffersWithDamageKHR 操作

第五阶段:SurfaceFlinger 开始合成图层,如果之前提交的 GPU 渲染任务没结束,则等待 GPU 渲染完成,再合成(Fence 机制),合成依然是依赖 GPU,不过这就是下一个任务了.这里对应的 Systrace 中的 SurfaceFlinger 主线程的 onMessageReceived 操作(包括 handleTransaction、handleMessageInvalidate、handleMessageRefresh)SurfaceFlinger 在合成的时候,会将一些合成工作委托给 Hardware Composer,从而降低来自 OpenGL 和 GPU 的负载,只有 Hardware Composer 无法处理的图层,或者指定用 OpenGL 处理的图层,其他的 图层偶会使用 Hardware Composer 进行合成

第六阶段 :最终合成好的数据放到屏幕对应的 Frame Buffer 中,固定刷新的时候就可以看到了。

下图表述了Android的图形管线:

图形的左侧是渲染器生产的graphics buffer,例如home界面,状态栏,system UI。SurfaceFlinger是排版者,硬件合成器是合成者。

Surface和SurfaceFlinger之间的数据交互,是通过BufferQueue来实现的。应用程序可以通过Surface的lockCanvas()方法获取一个Canvas对象,然后在Canvas上进行绘制操作。绘制完成后,应用程序可以调用unlockCanvasAndPost()方法将绘制好的图像数据发送到Surface对应的BufferQueue中。SurfaceFlinger会定期(根据VSYNC)从BufferQueue中获取最新的图像数据,并将其合成到屏幕上进行显示。

SurfaceFlinger和HWC(Hardware Composer)之间的数据交互,也是通过BufferQueue来实现的。HWC是Android系统中负责将图像数据发送给硬件显示设备的组件。SurfaceFlinger会将渲染好的图像数据放入BufferQueue中,然后通知HWC去获取图像数据进行显示。HWC会从BufferQueue中获取图像数据,并将其发送给硬件显示设备进行显示。

SurfaceFlinger和HWC之间的显示数据交换是双缓冲,但在某些情况下也可能会使用三缓冲机制。例如,在进行视频播放时,为了提高性能和流畅度,可能会使用三个缓冲区来实现更快的帧率。

整个绘制流程的节奏,分成两个生产者消费者模型,一个由屏幕和SurfaceFlinger构成,另一个由SurfaceFlinger和上层应用构成,具体流程可以用下图来描述:

也就是说,屏幕在显示完一帧后,发出的垂直同步除了通知帧缓冲区的切换之外,该消息还会发送到上层,通知上层开始绘制下一帧。

图像帧的读取显示

GraphicBuffer显示到屏幕上,也是跟像素一样的,一行一行地读取显示。当然,屏幕上的内容需要需要不断的更新,如果在同一个Buffer进行读取和写入(合成)操作,将会导致屏幕显示多帧内容。所以硬件层除了提供一个Buffer用于屏幕显示,还提供了一个Buffer用于后台的图形合成,也就是我们常说的双缓冲:

类图

下图是Android窗口子系统和图形子系统的相关类图:

  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值