| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> 【Android 图像显示系统】整体架构与缓冲区策略 -> 正文阅读 |
|
[移动开发]【Android 图像显示系统】整体架构与缓冲区策略 |
众所周知,Android中View的显示有三个主要方法,即onMeasure()、onLayout()、onDraw()。简单来说,它们分别负责测量——决定View的大小、布局——决定View在ViewGroup中的位置、和绘制——将View绘制到屏幕上。在onDraw()方法中,一般来说,我们实际上是完成了一张画布 canvas 的绘制。那这张画布到底是如何一步一步显示到屏幕上的呢?我们今天就来了解一下。 Android 图像显示系统整体架构先让我们来看一下 Android 图像显示系统的整体架构。 生产者消费者模型可以看出,这是个典型的生产者消费者模型,生产者产生渲染数据,消费者消耗渲染数据。 通过上图我们可以大概看到BufferQueue的工作过程:
图像流生产者 image stream produceers图像流生产方,即渲染数据的生产者,它可以是生成图形缓冲区以供消耗的任何内容,包括 OpenGL ES、Canvas 2D 和 mediaserver 视频解码器。 原生框架层 native framework以 Buffer Queue 为例,主要协助数据在生产者与消费者之间传输。 图像流消费者 image stream consumers图像流的最常见消费者是 SurfaceFlinger,该系统服务 System Service 会消耗当前可见的 Surface,并使用窗口管理器 WMS 中提供的信息将它们合成到屏幕。SurfaceFlinger 是可以修改所显示部分内容的唯一服务。SurfaceFlinger 使用 OpenGL 和 Hardware Composer 来合成一组 Surface。 Gralloc需要使用图形内存分配器 (Gralloc) 来分配图像生产方请求的内存。有关详情,请参阅 Gralloc HAL。 图像生产者从上面的架构图可知,图像的生产者主要有MediaPlayer,CameraPreview,NDK(即Skia),OpenGl ES。其中MediaPlayer和Camera Preview是通过直接读取图像源来生成图像数据,NDK(Skia),OpenGL ES是通过自身的绘制能力生产的图像数据。 OpenGL、Vulkan、Skia的区别
缓冲区 Buffer QueueBufferQueues 是 Android 图形组件之间的粘合剂,可以调解缓冲区从生产方到消耗方的固定周期。一旦生产方移交其缓冲区,SurfaceFlinger 便会负责将所有内容合成到显示部分。 黄油工程Google 在 2012 年的 I/O 大会上宣布了 Project Butter 黄油工程,并且在 Android 4.1 中正式开启了这个机制。若要了解该机制,我们先要了解一下VSYNC信号。 VSYNC信号VSYNC(Vertical Synchronization)是理解 Project Butter 的核心。 双缓存机制VSYNC信号的起始涉及早期显示器显示原理——显示器会将显存里的数据,按照从左至右,从上到下的顺序同步到屏幕上的每一个像素晶体管,一个像素晶体管就代表了一个像素。 当这个过程完成了,就表示一帧绘制完成了,此时显示器内部绘制图像的扫描点,即绘制“本张画”的“笔”会从右下角挪回左上角,扫描点移回的这个过程称为重置扫描点。 双缓冲虽然能解决效率问题,但会引入一个新的问题。我们知道,平常玩游戏时帧率都是波动的,这是因为忽略发热调度影响,GPU的性能是一定的,而我们的游戏场景是会变的,在低负载场景下,GPU处理的就快,帧率就高,而在高负载场景下GPU处理的就会慢一些,帧率就低。 拓展1 为什么游戏中开了垂直同步后会锁60帧?打开垂直同步之后,缓冲区的交换只在显示器绘制完成之后进行,如果显示器刷新率是60hz的话,自然就会锁在60帧了。 拓展2 目前手机、显示器市场的卖点——“高刷”有什么用?
根据前面的叙述,我们知道如果设备性能足够,显示器刷新率如果从60hz提升到120hz,那自然卡顿就会更小一点,帧与帧之间的延迟也会更低,观感上就是感觉高刷的画面更流畅。 In Android黄油工程之前具体到Android中,在Android4.1之前,屏幕刷新也遵循上面介绍的双缓存机制。 以时间的顺序来看下将会发生的过程:
呼之欲出的黄油工程为了解决这个问题,Google在Android 4.1系统中对Android Display系统进行了重构,实现了Project Butter(黄油工程):系统在收到VSync pulse后,将马上开始下一帧的渲染。即系统在收到VSync信号后,将马上开始下一帧的渲染。即一旦收到VSync通知(16ms触发一次),CPU和GPU 才立刻开始计算然后把数据写入buffer。如下图: CPU/GPU根据VSYNC信号同步处理数据,可以让CPU/GPU有完整的16ms时间来处理数据,减少了jank。 三缓存机制在Android 4.0之前,Android采用双缓冲机制,让绘制和显示器拥有各自的buffer:GPU 始终将完成的一帧图像数据写入到 Back Buffer,而显示器使用 Front Buffer。 双缓存机制的问题引入了垂直同步的双缓冲机制的理想前提是GPU性能足够,显示器只要绘制完毕就可以拿到下一帧的新数据,但现实往往与理想不同。如果界面比较复杂,或者设备硬件性能本身较低,CPU/GPU的处理时间较长,超过了16.6ms呢?双缓存机制会带来什么问题?如下图:
为什么 CPU 不能在第二个 16ms 处理绘制工作呢?原因是只有两个 buffer,缓存区backBuffer用于CPU/GPU图形处理,缓存区frameBuffer用于显示器显示。而此时Back buffer正在被GPU用来处理B帧的数据, Frame buffer的内容用于Display的显示,这样两个buffer都被占用,CPU 则无法准备下一帧的数据。 那么,如果再提供一个buffer,CPU、GPU 和显示设备都能使用各自的buffer工作,互不影响。 三缓冲机制三缓冲就是在双缓冲机制基础上增加了一个缓冲区TripleBuffer,这样可以最大限度的利用空闲时间,带来的坏处是多使用的一个Graphic Buffer所占用的内存。 第一个Jank,是不可避免的。但是在第二个 16ms 时间段,CPU/GPU 使用 第三个 Buffer 完成C帧的计算,虽然还是会多显示一次 A 帧,但后续显示就比较顺畅了,有效避免 Jank 的进一步加剧。总的来说,三缓冲机制有效利用了等待vysnc的时间,可以帮助我们减少了jank 。 RenderThread经过 Android 4.1 的 Project Butter 黄油计划之后,Android 的渲染性能有了很大的改善。不过,虽然利用了 GPU 的图形高性能运算,但是从计算 DisplayList,到通过 GPU 绘制到 Frame Buffer,整个计算和绘制都在 UI 主线程中完成。 硬件加速关于硬件加速,相信大家也经常听到,尤其是有些API不支持硬件加速,因此需要我们手动关闭,那么硬件加速到底是什么呢? CPU 与 GPU 的区别除了屏幕,UI 渲染还要依赖另外两个核心的硬件:CPU 和 GPU。
Rasterization 栅格化是绘制那些 Button、Shape、Path、String、Bitmap 等显示组件最基础的操作。栅格化将这些 UI 组件拆分到显示器的不同像素上进行显示。这是一个非常耗时的操作,GPU 的引入就是为了加快栅格化。 拓展3 挖矿为什么用显卡不用CPU?先来介绍一下挖矿是什么。 什么是挖矿?所谓的矿就是一个个数据包,这些数据包需要解密。矿的数据包中含有少量的网络虚拟货币——比特币。比特币的本质其实就是一堆复杂算法所生成的特解,即方程组所能得到有限个解中的一组。以钞票来比喻的话,比特币就是钞票的冠字号码,你知道了某张钞票上的冠字号码,你就拥有了这张钞票。 为什么用显卡挖矿?既然是计算工作,为什么现在矿老板们都是使用显卡挖矿,不使用CPU呢? 硬件绘制与软件绘制硬件绘制的思想就是通过底层软件代码,将 CPU 不擅长的图形计算转换成 GPU 专用指令,由 GPU 完成绘制任务。所以说硬件加速的本质就是使用GPU代替CPU完成Graphic Buffer绘制工作,以实现更好的性能。 图像消费者当生产者把绘制好的GraphicBuffer数据放入BufferQueue后,接下来的工作就是以SurfaceFlinger为代表的消费者来完成了。
总结总的来说,Android图像渲染流程可如下图所示:
推荐阅读生产者消费者问题、读者写者问题、哲学家问题细致讲解_Infinity_and_beyond的博客-CSDN博客_生产者消费者问题和读者写者问题 |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 3:52:15- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |