Android 渲染机制 —— (显示原理全过程解析)
Posted 冬天的毛毛雨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 渲染机制 —— (显示原理全过程解析)相关的知识,希望对你有一定的参考价值。
帧率
每秒的帧数(fps) 或者说帧率是以帧为单位的位图图像每秒连续出现在显示器上的次数(速率)。简单来说就是一秒钟,屏幕显示多少张画面。
为什么是 60fps ?
界面刷新渲染依赖底层的VSYNC 信号,VSYNC 信号以每秒 60 次的频率发送给上层。
开发 app 的性能目标就是保持 60fps,这意味着每一帧你只有 1000/60=16.67ms 的时间来处理所有的任务。**如果 16ms 内没有办法把这一帧的任务执行完毕,就会发生丢帧的现象。**丢帧越多,用户感受到的卡顿情况就越严重。
OpenGL ES
是手持嵌入式设备的 3D API ,跨平台的、功能完善的2D 和 3D 图形应用程序接口 API, 有一套固定渲染管道流程。
DisplayList
在android 把XML 布局文件转换成 GPU 能够识别并绘制的对象。这个操作是在 DisplayList 的帮助下完成的。
DisplayList 持有所有将要交给 GPU绘制到屏幕上的数据信息。
频率与性能
大多数用户感知到的卡顿等性能问题的最主要根源都是因为 渲染性能,也就是 16ms 内没有办法把这一帧的任务执行完毕,发生了丢帧的现象。从设计师和产品的角度,他们希望 App 能够有更多的动画、图片等时尚元素来实现流畅的用户体验。但是 Android 系统很有可能无法及时完成那些复杂的界面渲染操作。Android 系统每隔 16ms 发出 VSYNC 信号,触发对 UI 进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的 60fps,为了能够实现 60fps,这意味着程序的大多数操作都必须在 16ms 内完成。
如果 App 的某个操作花费时间是 24ms,系统在得到 VSYNC 信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在 32ms 内看到的会是同一帧画面。
通常,越复杂的 UI,越容易导致卡顿,例如,用户容易在 UI 执行动画或者滑动 ListView 的时候感知到卡顿不流畅,是因为这里的操作相对复杂,容易发生丢帧的现象,从而感觉卡顿。有很多原因可以导致丢帧,也许是因为你的 layout 太过复杂,无法在 16ms 内完成渲染,有可能是因为你的 UI 上有层叠太多的绘制单元,还有可能是因为动画执行的次数过多。这些都会导致 CPU 或者 GPU 负载过重。
渲染与 CPU 和 GPU 的关系
由于 CPU 和 GPU 的设计不同,CPU 更擅长复杂逻辑控制,而 GPU 得益于大量 ALU 和并行结构设计,更擅长数学运算。在 Android 中,页面由各种基础元素(DisplayList)构成,渲染时需要进行大量浮点运算,这些工作更适合交给 GPU 来做。Android 为了提高视图渲染的性能,在 Android 3.0 中引入了硬件加速。这样,Android 就有两种绘制模型:基于软件的绘制模型、硬件加速绘制模型。
在 Android 系统中,CPU 与 GPU 的分工不同:
-
CPU 主要负责包括 Measure,Layout,Record,Execute 的计算操作,
-
GPU 主要负责 **Rasterization(栅格化)**操作。
栅格化是指将向量图形格式表示的图像转换成位图(像素)以用于显示设备输出的过程,简单来说就是将我们要显示的视图,转换成用像素来表示的格式。栅格化是一个非常耗时的工作。
CPU 与 GPU 职责对比
为了简单说明 CPU 和 GPU 的职责工作,请看下图:
该图简单说明CPU和GPU的职责工作,以及可能发生的问题和解决方案。
CPU 产生的问题:不必要的布局和失效
在 CPU 方面,最常见的性能问题是不必要的布局和失效,这些内容必须在视图层次结构中进行测量、清除并重新创建。引发这种问题通常有两个原因:
-
重建显示列表的次数太多。(DisplayList )
-
花费太多时间作废视图层次并进行不必要的重绘。
这两个原因在更新显示列表或者其他缓存 GPU 资源时导致 CPU 工作过度。
GPU 产生的问题:过度绘制(overdraw)
在 GPU 方面,最常见的问题是我们所说的过度绘制(overdraw),通常是在像素着色过程中,通过其他工具进行后期着色时浪费了 GPU 处理时间。下面我们对 GPU 和 CPU 产生的两大问题进行优化。
GPU 的绘制过程 ,就跟刷墙一样,一层层进行,16ms刷一次,这样就会造成图层覆盖的现象,即无用的图层还被绘制在底层,造成不必要的浪费。
过度绘制查看工具
在手机端的开发者选项里,有OverDraw检测工具,调式GPU 过度绘制工具,
其中颜色代表渲染的图层情况,分别代表1层,2层,3层,4层覆盖。
Overdraw 有时候是因为你的UI布局存在大量重叠的部分,还有的时候是因为非必须的重叠背景。例如某个Activity有一个背景,然后里面的Layout又有自己的背景,同时子View又分别有自己的背景。仅仅是通过移除非必须的背景图片,这就能够减少大量的红色Overdraw区域,增加蓝色区域的占比。这一措施能够显著提升程序性能。
计算渲染的耗时
任何时候 View 的绘制内容发生变化后,都会重新执行创建 DisplayList , 渲染 DisplayList , 更新到屏幕上等一系列操作。这个流程的表现性能取决于你的View的复杂程度,View的状态变化以及渲染管道的执行性能。
优化
在 Android 里面那些由主题所提供的资源,比如 Bitmaps Drawables 都是一起打包到统一的 Texture 纹理当中,然后再传递到 GPU 里面,这意味着每次需要用这些资源的时候,都是直接从纹理里面进行获取渲染的。
扁平化处理,防止过度绘制
当背景无法避免,尽量用 Color.TRANSPARENT
因为透明色 Color.TRANSPARENT 是不会被渲染的,它是透明的。
//优化前
//优化前: 当图片不为空,ImageView加载图片,然后统一设置背景
Bean bean=list.get(i);
if (bean.img == 0) {
Picasso.with(getContext()).load(bean.img).into(holder.imageView);
}
chat_author_avatar.setBackgroundColor(bean.backPic);
//优化后
//优化后:当图片不为空,ImageView加载图片,并设置背景为TRANSPARENT;
//当图片为空,ImageView加载TRANSPARENT,然后设置背景为无照片背景
Bean bean=list.get(i);
if (bean.img == 0) {
Picasso.with(getContext()).load(android.R.color.transparent).into(holder.imageView);
holder.imageView.setBackgroundColor(bean.backPic);
} else {
Picasso.with(getContext()).load(bean.img).into(holder.imageView);
holder.imageView.setBackgroundColor(Color.TRANSPARENT);
}
手机像素哪里来?
Frame Buffer 和 Back Buffer
手机屏幕是由许多的像素点组成的,通过让每一个像素点显示不同的颜色,可以组合成各种各样的图像。这些像素点的颜色数据从哪里来?
GPU 控制的一块缓冲区中,这块缓冲区叫做 Frame Buffer(帧缓冲区)。可以简单理解为一个二维数组,数组中的每一个元素对应着手机屏幕上的一个像素点,元素的值代表着屏幕上对应的像素点要显示的颜色。
优化屏幕画面不断变化,需要这个buffer不断地更新数据。一个 FramBuffer 是忙不过来的。
因此GPU 除了 Back Buffer ,用以交给手机屏幕进行绘制外,还有一个缓冲区,叫 Back Buffer (用来交给你的应用),让你往里面填充数据。
GPU 会定期地交换 Back Buffer 和 Frame Buffer ,也就是让 Back Buffer 变成 Frame Buffer 交给屏幕进行绘制,让原来的 Frame Buffer 变成 Back Buffer 交给你的应用进行绘制。交换的频率也是60次/秒,这就与屏幕硬件电路的刷新频率保持了同步。
GPU
Android 是如何利用 GPU 进行画面渲染的呢?
一个很直接的问题是:Activity 的画面是如何绘制到屏幕上的?那些复杂的 XML 布局文件又是如何能够被识别并绘制出来的?
Resterization 栅格化是绘制那些 Button,Shape,Path,String,Bitmap 等组件最基础的操作。它把那些组件拆分到不同的像素上进行显示。这是一个很费时的操作,GPU 的引入就是为了加快栅格化的操作。
CPU
CPU 负责把 UI 组件计算成 Polygons,Texture 纹理,然后交给 GPU 进行栅格化渲染。
这里想一个问题:CPU 是如何将数据传递给 GPU 的呢?
每次从 CPU 转移到 GPU 是一件很麻烦的事情,所幸的是 OpenGL ES 可以把那些需要渲染的纹理 Hold 在 GPU Memory 里面,在下次需要渲染的时候直接进行操作。所以如果你更新了 GPU 所 Hold 住的纹理内容,那么之前保存的状态就丢失了。
在 Android 里面那些由主题所提供的资源,例如 Bitmaps,Drawables 都是一起打包到统一的 Texture 纹理当中,然后再传递到 GPU 里面,这意味着每次你需要使用这些资源的时候,都是直接从纹理里面进行获取渲染的。当然随着 UI 组件的越来越丰富,有了更多演变的形态。例如显示图片的时候,需要先经过 CPU 的计算加载到内存中,然后传递给 GPU 进行渲染。文字的显示比较复杂,需要先经过 CPU 换算成纹理,然后交给 GPU 进行渲染,返回到 CPU 绘制单个字符的时候,再重新引用经过 GPU 渲染的内容。动画则存在一个更加复杂的操作流程。
渲染流程线:
Android 渲染机制
Android 系统采用一种称为 Surface 的UI 架构为应用程序提供用户界面。
在Android 应用程序中,每一个Activity 组件都关联有一个或者若干个窗口,每一个窗口都对应有一个Surface 。有了这个Surface之后,应用程序就可以在上面渲染窗口的UI。
最终这些已经绘制好了的Surface 都会被统一提交给Surface 管理服务 SurfaceFlinger 进行合成,最后显示在屏幕上面。
无论是应用程序,还是SurfaceFlinger ,都可以利用GPU 等硬件来进行UI渲染,以获得更流畅的UI.
总结: Android 应用程序调用SurfaceFlinger 服务把经过测量、布局和绘制后的Surface 渲染到显示屏幕上。
重要成员:
-
ViewRootImpl: 用来控制窗口的渲染,以及用来与WindowManagerService 、SurfaceFlinger 通信。
-
WindowManager : WindowManager 会控制窗口对象,它们是用于容纳视图对象的容器。窗口对象始终由Surface 对象提供支持。WindowManager 会监督生命周期、输入和聚焦事件、屏幕方向、转换、动画、位置、变形、Z轴顺序以及窗口的许多其他方面。
WindowManager 会将所有窗口元数据发送到SurfaceFlinger ,以便SurfaceFlinger 可以使用这些数据在屏幕上合成Surface.
-
Surface : Andriod 应用的每个窗口对应一个画布(Canvas) ,即Surface ,可以理解为 Android 应用程序的一个窗口。Surface 是一个接口,供生产方与使用方交换缓冲区。
-
SurfaceView : SurfaceView 是一个组件,可用于在View 层次结构中嵌入其他合成层。SurfaceView 采用与其他 View 相同的布局参数,因此可以像对待其他任何 View 一样对其进行操作,但 SurfaceView 的内容是透明的。当 SurfaceView 的 View 组件即将变得可见时,框架会要求 SurfaceControl 从 SurfaceFlinger 请求新的 Surface。
-
BufferQueue:BufferQueue 类将可生成图形数据缓冲区的组件(生产方)连接到接受数据以便进行显示或进一步处理的组件(使用方)。几乎所有在系统中移动图形数据缓冲区的内容都依赖于 BufferQueue。
-
SurfaceFlinger:Android 系统服务,负责管理 Android 系统的帧缓冲区,即显示屏幕。 EGLSurface 和 OpenGL ES:OpenGL ES (GLES) 定义了用于与 EGL 结合使用的图形渲染 API。EGI 是一个规定如何通过操作系统创建和访问窗口的库(要绘制纹理多边形,请使用 GLES 调用;要将渲染放到屏幕上,请使用 EGL 调用)。
-
Vulkan:Vulkan 是一种用于高性能 3D 图形的低开销、跨平台 API。与 OpenGL ES 一样,Vulkan 提供用于在应用中创建高质量实时图形的工具。
Android 图形架构图
Android 图形架构图,显示了关键组件如何协同工作:
图形系统使用生产者-消费者模式,根据框架图,可以看出基本的操作流程:
图形生产者创建一个 Surface,将图形数据画到 Surface 上。
Surface 使用的图形缓冲是通过 Gralloc 来分配的。
图形生产者的窗口信息由 WindowManager 管理,WindowManager 将窗口元数据发送给 SurfaceFlinger 进行合成。
图形消费者处理图形生产者产生的数据。当图形数据用于屏幕显示时,SurfaceFlinger 使用窗口元数据将图形缓冲合成到显示上。
图形数据最终渲染到显示设备上是通过 Hardware Composer 完成的。硬件一般支持多个显示层,如果显示层可以满足 Surface 的需求,则可以将所有可见 Surface 发送给 Hardware Composer 进行合成。也可以使用 GPU 预先完成一些 Surface 数据的合成工作,之后再送给 Hardware Composer。
图像流生产方
图像流生产方可以是生成图形缓冲区以供消耗的任何内容。例如 OpenGL ES、Canvas 2D 和 mediaserver 视频解码器。
图像流消耗方
图像流的最常见消耗方是 SurfaceFlinger,该系统服务会消耗当前可见的 Surface,并使用窗口管理器中提供的信息将它们合成到显示部分。SurfaceFlinger 是可以修改所显示部分内容的唯一服务。SurfaceFlinger 使用 OpenGL 和 Hardware Composer 来合成一组 Surface。
其他 OpenGL ES 应用也可以消耗图像流,例如相机应用会消耗相机预览图像流。非 GL 应用也可以是使用方,例如 ImageReader 类。
硬件混合渲染器
显示子系统的硬件抽象实现。SurfaceFlinger 可以将某些合成工作委托给 Hardware Composer,以分担 OpenGL 和 GPU 上的工作量。SurfaceFlinger 只是充当另一个 OpenGL ES 客户端。因此,在 SurfaceFlinger 将一个或两个缓冲区合成到第三个缓冲区中的过程中,它会使用 OpenGL ES。这样使合成的功耗比通过 GPU 执行所有计算更低。
Hardware Composer HAL 则进行另一半的工作,并且是所有 Android 图形渲染的核心。Hardware Composer 必须支持事件,其中之一是 VSYNC(另一个是支持即插即用 HDMI 的热插拔)。
Gralloc 用来分配图形生产方请求的内存。
Gralloc
需要使用图形内存分配器 (Gralloc) 来分配图像生产方请求的内存。通常由 SurfaceFlinger 申请并将显示内容存储到缓存中,供 HAL 使用。
接下来,我们来看,Android 是如何将一个 xml 布局渲染到屏幕上的。我们可以将渲染过程简单分为两个部分:应用程序侧绘制和系统侧渲染。
应用侧绘制
一个 Android 应用程序窗口里面包含了很多 UI 元素,它们是以树形结构来组织的,父视图包含子视图,一个窗口的根视图是 DecorView 对象,ViewRootImpl 负责与系统进程进行通信。
在绘制一个 Android 应用程序窗口的 UI 之前,我们首先要确定它里面的各个子 UI 元素在父 UI 元素里面的大小以及位置。确定各个子 UI 元素在父 UI 元素里面的大小以及位置的过程又称为测量过程和布局过程。因此,Android 应用程序窗口的 UI 渲染过程可以分为测量、布局和绘制三个阶段,最后生成 Display List。
如下图所示:
- 测量:递归(深度优先)确定所有视图的大小(高、宽)
- 布局:递归(深度优先)确定所有视图的位置(左上角坐标)
- 绘制:在画布 canvas 上绘制应用程序窗口所有的视图
- 生成 Display List 数据。
测量、布局负责确定每个视图组件的大小和位置信息,接下来就是绘制了。
Android 有两种绘制模型:基于软件的绘制模型和硬件加速的绘制模型。参见:《Android 渲染机制——绘制模型》。
Android 需要把 XML 布局文件转换成 GPU 能够识别并绘制的对象。这个操作是在 DisplayList 的帮助下完成的。Display List 持有所有将要交给 GPU 绘制到屏幕上的数据信息。
关于 Display List 相关内容,请参考前文:《Android 渲染机制——Display List》。
系统侧渲染
1. Display List 数据交由GPU 进行渲染处理
Android 需要把 XML 布局文件转换成 GPU 能够识别并绘制的对象。这个操作是在 DisplayList 的帮助下完成的。Display List 持有所有将要交给 GPU 绘制到屏幕上的数据信息。
Display List 是一个缓存绘制命令的 Buffer,Display List 的本质是一个缓冲区,它里面记录了即将要执行的绘制命令序列。渲染 Display List,发生在应用程序进程的 Render Thread 中。增加 Render Thread 线程,也是为了避免 UI 线程任务过重,用于提高渲染性能。
这些绘制命令最终会转化为 Open GL 命令由 GPU 执行。这意味着我们在调用 Canvas API 绘制 UI 时,实际上只是将 Canvas API 调用及其参数记录在 Display List 中,然后等到下一个 VSYNC 信号到来时,记录在 Display List 里面的绘制命令才会转化为 Open GL 命令由 GPU 执行。
2. GPU渲染处理
Android 使用 OpenGL ES (GLES) API 渲染图形。GPU 将视图栅格化后,生成 Surface。GPU 作为图像流生产方将显示内容,最终发送给图像流的消耗方 SurfaceFlinger。
大多数客户端使用 OpenGL ES 或 Vulkan 渲染到 Surface 上(硬件加速,使用了 GPU 渲染)。但是,有些客户端使用画布渲染到 Surface 上(未使用硬件加速)。
3.生成Surface 并存储到 BufferQueue
Surface 对象使应用能够渲染要在屏幕上显示的图像。通过 SurfaceHolder 接口,应用可以编辑和控制 Surface。Surface 是一个接口,供生产方与使用方交换缓冲区。
SurfaceHolder 是系统用于与应用共享 Surface 所有权的接口。与 Surface 配合使用的一些客户端需要 SurfaceHolder,因为用于获取和设置 Surface 参数的 API 是通过 SurfaceHolder 实现的。一个 SurfaceView 包含一个 SurfaceHolder。与 View 交互的大多数组件都涉及到 SurfaceHolder。如果你开发的是相机相关的应用,会涉及到相关 API 的使用。
通常 SurfaceFlinger 使用的缓冲区队列是由 Surface 生成的,当渲染到 Surface 上时,结果最终将出现在传送给消费者的缓冲区中。Canvas API 提供一种软件实现方法(支持硬件加速),用于直接在 Surface 上绘图(OpenGL ES 的低级别替代方案)。与视图有关的任何内容均涉及到 SurfaceHolder,其 API 可用于获取和设置 Surface 参数(如大小和格式)。
BufferQueue 是 SurfaceFlinger 使用的缓冲区队列,而 Surface 是 BufferQueue 的生产方。BufferQueue 类将可生成图形数据缓冲区的组件(生产方)连接到接受数据以便进行显示或进一步处理的组件(使用方,例如 SurfaceFlinger)。几乎所有在系统中移动图形数据缓冲区的内容都依赖于 BufferQueue。
用于显示 Surface 的 BufferQueue 通常配置为三重缓冲。缓冲区是按需分配的,因此,如果生产方足够缓慢地生成缓冲区(例如在 60 fps 的显示屏上以 30 fps 的速度进行缓冲),队列中可能只有两个分配的缓冲区。按需分配缓冲区有助于最大限度地减少内存消耗。
数据处理过程:
上图描述了图形管道的流程。左侧为图形生产者,右侧为图形消费者,中间通过 BufferQueues 连接。图中,主屏幕、状态栏和系统界面通过 GPU 渲染生成图形缓冲区,做为生产者传递给 BufferQueues。SurfaceFlinger 做为消费者,接收到 BufferQueues 的通知后,取出可用的图形缓冲区,送给显示端。例图中将状态栏和系统界面的图形缓冲送给 GPU 合成,生成新的图形缓冲后再通过 BufferQueues 发送到硬件混合渲染器。
注意:SurfaceFlinger 创建并拥有 BufferQueue 数据结构,并且可存在于与其生产方不同的进程中。
4. SurfaceFlinger 将显示数据发送给显示屏
SurfaceFlinger 接受来自多个源的数据缓冲区,然后将它们进行合成并发送到显示屏。
WindowManager 为 SurfaceFlinger 提供缓冲区和窗口元数据,而 SurfaceFlinger 可使用这些信息将 Surface 合成到屏幕。
SurfaceFlinger 可通过两种方式接受缓冲区:通过 BufferQueue 和 SurfaceControl,或通过 ASurfaceControl。
上文中,我们已经介绍了 BufferQueue。ASurfaceControl 是 Android 10 新增的,这是 SurfaceFlinger 接受缓冲区的另一种方式。
ASurfaceControl 将 Surface 和 SurfaceControl 组合到一个事务包中,该包会被发送至 SurfaceFlinger。ASurfaceControl 与层相关联,应用可通过 ASurfaceTransactions 更新该层。然后,应用可通过回调(用于传递包含锁定时间、获取时间等信息的 ASurfaceTransactionStats)获取有关 ASurfaceTransactions 的信息。
SurfaceFlinger 和 WMS 之间的交互过程
SurfaceFlinger 接受缓冲区的一种方式是通过 BufferQueue 和 SurfaceControl .
当应用进入前台时,它会从 WindowManager 请求缓冲区。
然后,WindowManager 会从SurfaceFlinger 请求层。(surface(包含BufferQueue) 和 SurfaceControl (包含屏幕框架等层元数据)的组合。
SurfaceFlinger 创建层并将其发送至WindowManager 。
然后,WindowManager 将 Surface 发送至应用,但会保留 SurfaceControl 来操控应用在屏幕上的外观。
在屏幕处于两次刷新之间时,屏幕会向 SurfaceFlinger 发送 VSYNC 信号。VSYNC 信号表明可对屏幕进行刷新而不会产生撕裂。当 SurfaceFlinger 接收到 VSYNC 信号后,SurfaceFlinger 会遍历其层列表,以查找新的缓冲区。如果 SurfaceFlinger 找到新的缓冲区,SurfaceFlinger 会获取缓冲区;否则,SurfaceFlinger 会继续使用上一次获取的那个缓冲区。SurfaceFlinger 必须始终显示内容,因此它会保留一个缓冲区。如果在某个层上没有提交缓冲区,则该层会被忽略。
SurfaceFlinger 在收集可见层的所有缓冲区之后,便会询问硬件混合渲染器 (HWC) 应如何进行合成。如果 HWC 将层合成类型标记为客户端合成,则 SurfaceFlinger 将合成这些层。然后,SurfaceFlinger 会将输出缓冲区传递给 HWC。
注:SurfaceFlinger 更详细的说明,请查看前文《Android 渲染机制——SurfaceFlinger》。
总结
-
帧率是以帧为单位的位图图像每秒连续出现在显示器上的次数(速率)。简单来说就是一秒钟,屏幕显示多少张画面。
-
Android 在设计的时候,把帧频限定在了每秒 60 帧,当我们的 APP 的帧频 60fps 时,画面就会非常的流畅。
-
界面刷新渲染依赖底层的 VSYNC 信号,VSYNC 信号以每秒 60 次的频率发送给上层,并且高于 60fps 的帧频也是没有必要的,因为人眼与大脑之间的协作无法感知超过 60fps 的画面更新。
-
大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能,也就是 16ms 内没有办法把这一帧的任务执行完毕,发生了丢帧的现象。
-
由于 CPU 和 GPU 的设计不同,CPU 更擅长复杂逻辑控制,而 GPU 得益于大量 ALU 和并行结构设计,更擅长数学运算。在 Android 系统中,CPU 与 GPU 的分工不同,CPU 主要负责包括 Measure,Layout,Record,Execute 的计算操作,GPU 主要负责 Rasterization(栅格化)操作。
-
Android 为了提高视图渲染的性能,在 Android 3.0 中引入了硬件加速。
-
在 Android 应用程序中,每一个 Activity 组件都关联有一个或者若干个窗口,每一个窗口都对应有一个 Surface。有了这个 Surface 之后,应用程序就可以在上面渲染窗口的 UI。最终这些已经绘制好了的 Surface 都会被统一提交给 Surface 管理服务 SurfaceFlinger 进行合成,最后显示在屏幕上面。无论是应用程序,还是 SurfaceFlinger,都可以利用 GPU 等硬件来进行 UI 渲染,以便获得更流畅的 UI。
-
一句话来概括一下 Android 应用程序显示的过程:Android 应用程序调用 SurfaceFlinger 服务把经过测量、布局和绘制后的 Surface 渲染到显示屏幕上。
-
图形生产者创建一个 Surface,将图形数据画到 Surface 上。Surface 使用的图形缓冲是通过 Gralloc 来分配的。 图形生产者的窗口信息由 WindowManager 管理,WindowManager 将窗口元数据发送给 SurfaceFlinger 进行合成。 图形消费者处理图形生产者产生的数据。当图形数据用于屏幕显示时,SurfaceFlinger 使用窗口元数据将图形缓冲合成到显示上。图形数据最终渲染到显示设备上是通过 Hardware Composer 完成的。
-
Android 需要把 XML 布局文件转换成 GPU 能够识别并绘制的对象。这个操作是在 DisplayList 的帮助下完成的。Display List 持有所有将要交给 GPU 绘制到屏幕上的数据信息。
-
Display List 是一个缓存绘制命令的 Buffer,Display List 的本质是一个缓冲区,它里面记录了即将要执行的绘制命令序列。渲染 Display List,发生在应用程序进程的 Render Thread 中。增加 Render Thread 线程,也是为了避免 UI 线程任务过重,用于提高渲染性能。
-
Android 使用 OpenGL ES (GLES) API 渲染图形。GPU 将视图栅格化后,生成 Surface。GPU 作为图像流生产方将显示内容,最终发送给图像流的消耗方 SurfaceFlinger。
-
BufferQueue 是 SurfaceFlinger 使用的缓冲区队列,而 Surface 是 BufferQueue 的生产方。BufferQueue 类将可生成图形数据缓冲区的组件(生产方)连接到接受数据以便进行显示或进一步处理的组件(使用方,例如 SurfaceFlinger)。
-
SurfaceFlinger 接受来自多个源的数据缓冲区,然后将它们进行合成并发送到显示屏。WindowManager 为 SurfaceFlinger 提供缓冲区和窗口元数据,而 SurfaceFlinger 可使用这些信息将 Surface 合成到屏幕。
以上是关于Android 渲染机制 —— (显示原理全过程解析)的主要内容,如果未能解决你的问题,请参考以下文章