Android 上屏原理

为了方便理解核心原理,以下流程均已精简。

一. 完整流程

流程图:


基础流程

上图是 Android 将一个布局通过硬件渲染的方式显示到屏幕,这个过程可简化为俩步:应用侧绘制和系统侧绘制。

  • 应用侧

通过树形结构组织 UI 元素,通过 measure、layout、draw 三个阶段,在 canvas 上绘制出应用程序窗口的所有视图,最终生成一个缓存绘制命令的 Buffer -- DisplayList。

这一过程是在 CPU 里计算完成的。

  • 系统侧

为了提高渲染性能,Android 3.0 起提供了硬件加速,将部分绘制工作交给 GPU 完成。 GPU 主要负责栅格化,可以简单理解为将向量图形格式表示的图像转换成位图(像素)以用于显示设备输出的过程。

因此在系统侧,首先将 DisplayList 转为 GPU 可以识别的 OpenGL 指令,然后由 GPU 使用 OpenGL ES API 将图像渲染到 Surface 上。接下来,可以(简单的)理解为一个图形数据缓冲交换的生产消费模型:

BufferQueue 是供生产消费者使用的图形数据缓冲区队列;Surface 作为生产者,提供了应用渲染上屏图像的能力,通过 GPU 渲染生成的图形缓冲区,最终通过 Surface 传递给 BufferQueue;SurfaceFlinger 作为消费者,接收来自多个源的数据缓冲区,它在接收到 BufferQueues 的通知后,取出可用的图形缓冲区,发送(或合成后发送,取决于 HWC)给 HWC。

HWC 是硬件混合渲染器,它负责合成所有图层并直接写入输出到帧缓冲,帧缓冲的数据最终会转为适当的信号发送给显示器完成最后的上屏。

上图中的 vsync 指同步,并非下文中的 Vsync 信号。

二. 显示器的图形显示

以下内容涉及显示器显示图像的基础硬件知识。

显示器必须通过图形显示子系统中的显示控制部件才能完成显示,常见的图形显示子系统有光栅扫描子系统,这里将介绍如何通过光栅扫描子系统在显示器上显示图像。

光栅扫描子系统有俩个重要的部件:帧缓冲存储器(即显存)和显示控制器。

帧缓冲存储器是用来存储像素颜色(灰度)的存储器,可由显示控制器直接访问,以便随时刷新屏幕。前文中的帧缓冲即存储在这里。

显示控制器可看作是一个独立于 CPU 的本地处理器(实际仍然由 CPU 控制),它的主要功能是依据设定的显示方式,自主地、反复不断的读取显存中的图像点阵数据,将它们转为 R、G、B 三色信号并配以同步信号送至显示器,即可刷新屏幕。

由于计算像素数据并写入相应的帧缓冲单元计算量相当大,为了减轻 CPU 的负担,诞生了独立的显示模块:显卡,它除了包含显示控制器、帧缓冲存储器(显存)外,还增加了独立的显示处理器(GPU)和显示处理器存储区域(主要用于临时存放显示处理时的程序和数据)。

三*. OpenGL 渲染管线

通过 OpenGL 渲染管线,可以将一张特定尺寸的 Bitmap,最终采样并显示在不同尺寸分辨率的显示器上。
OpenGL 渲染管线的基本流程如下,其中,光栅化会把图元映射为最终屏幕上相应的像素,片段着色器即对要渲染的每个像素单元着色。

渲染管线

抛开 Android,如果有兴趣了解如何使用 OpenGL 去加载图片、并对图片进行处理(给图片增加各种效果)和渲染,可见此代码演示 -- Github 链接

另外对于 Bitmap 的绘制,Bitmap 持有像素数据,而像素数据可以转为 OpenGL 需要的 Texture,进而采样完成渲染到 Surface。

四. 黄油计划

为了提升 Android 屏幕渲染的流畅度,从 Android 4.1 开始对显示系统进行了重构,称之为黄油计划。
黄油计划引入了三个核心元素:VSYNC、Tripple Buffer 和 Choreographer。

  • VSYNC

一种定时中断机制,它的作用是使 CPU 在收到 VSYNC 信号后,马上开始处理下一帧的数据(结合 Handler 的同步屏障机制),并保证刷新率和帧率的同步。

它的好处有俩个:在帧率 > 刷新率的情况下,GPU 所产生的帧数据会因为等待 VSYNC 的刷新信息而被 Hold 住,这样能够保持每次刷新都有实际的新的数据可以显示,以防止画面撕裂;在帧率 < 刷新率的情况下,它能提升渲染任务的优先级来减少丢帧。

  • Tripple Buffer

三重缓冲机制,当使用双缓存机制、且 GPU 或 CPU 计算超时时,由于屏幕显示占用一个缓存、计算中的 GPU 或 CPU 占用另一个缓存,因此在单帧时间内,必定有 CPU 或 GPU 处于空闲状态,三缓冲机制可以弥补该空缺,进一步提升流畅度。

  • Choreographer

用于从显示子系统接收定时脉冲(例如 VSYNC 信号),然后安排工作以渲染下一个显示帧。它可以协调动画(animations)、输入(input)、绘制(drawing) 三个 UI 相关的操作。

五. 绘制的触发

第一节简述了绘制开始后,单帧绘制数据从应用侧、系统侧直到上屏的过程。

由于绘制是在收到 Vsync 信号才开始的,而请求绘制则可以在任意时间点(如手动调用 invalidate),所以本节将补充从请求绘制到绘制开始的这段时间节点里发生了什么。

绘制触发.png

要点:

  1. 界面不变时,底层也会以固定的屏幕刷新率(如 16.6 ms)来切换每一帧的画面。但对 App 而言,只有注册了下一个 Vsync 信号才能接收到回调、重新绘制。如果界面不变,App 不会接收 Vsync 事件,CPU/GPU 也就不会走绘制流程。
  2. 当请求绘制时,系统会添加同步屏障,阻止 MessageQueue 中同步消息的执行。此后无论是 Choreographer 注册下一个 Vsync 信号的过程、还是 Choreographer 接收 Vsync 信号执行 Callback 的过程中,都会发送异步消息优先执行。
  3. 由于直到 Vsync 信号到来并绘制后同步屏障才会移除,所以同步消息最多被延迟一帧执行。有时为了让我们的任务尽快执行,可以发送异步消息,这样便可以在等待 Vsync 信号期间执行任务,但需要注意异步任务无法保证与绘制任务的顺序关系。
  4. 当请求绘制时,绘制任务不会立即开始,而是等到下一个 Vsync 信号到来时才开始;当 CPU&GPU 绘制流程执行完毕,界面也不会立即刷新,而是等到再下一个 Vsync 信号到来才进行缓存交换并显示。
  5. 同步屏障 + Vsync 并不能保证绘制一定在固定的 Vsync 信号点执行,原因是添加同步屏障的时间点之前可能在执行一个耗时的同步任务。所以造成丢帧的原因有俩个:1. 主线程在执行耗时任务导致绘制任务不能开始;2. CPU&GPU 绘制 View 超过了单帧的时间。

六. 参考链接

Android 显示刷新机制、VSYNC和三重缓存机制
Android 黄油计划和显示刷新机制学习笔记
Android 渲染机制——原理篇(显示原理全过程解析)
掌握Android图像显示原理上
计算机图形学基础 -- 第三版
Android-Choreographer原理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,200评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,526评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,321评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,601评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,446评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,345评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,753评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,405评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,712评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,743评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,529评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,369评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,770评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,026评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,301评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,732评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,927评论 2 336

推荐阅读更多精彩内容

  • 更新:最近发现该篇文章阅读的人数挺多,并且也发现了更好的关于Android显示系统的文章,所以将关于Android...
    htkeepmoving阅读 9,560评论 0 10
  • 作者:yearzhu,2011年进入腾讯公司,从事过Web端及移动端的测试工作,喜爱新鲜事物及新技术,目前在SNG...
    Viking_Den阅读 882评论 0 5
  • 3.2 Android显示原理 Android应用程序的显示过程包含了两个部分(应用侧绘制、系统侧渲染)、两个机制...
    jianhuih阅读 2,573评论 1 6
  • 对于Android开发者来说,我们或多或少有了解过Android图像显示的知识点,刚刚学习Android开发的人会...
    子者不语阅读 1,376评论 0 5
  • iOS 提供了非常丰富且性能优越的 UI 工具栈,加上自己底层已经做了足够好的优化,直接使用 UIKit 库的基本...
    HughKaun阅读 1,330评论 0 2