Android VSYNC双Buffer与三Buffer渲染线程RenderThread(5)
手机自带的卡顿丢帧分析工具,柱状图:
帧的大体绘制过程:
帧绘制中的重要概念:BufferQueue
首先看一下 BufferQueue,BufferQueue 是一个生产者(Producer)-消费者(Consumer)模型中的数据结构,一般来说,消费者(Consumer) 创建 BufferQueue,而生产者(Producer) 一般不和 BufferQueue 在同一个进程里面
当生产者(Producer) 需要 Buffer 时,它通过调用 dequeueBuffer()并指定 Buffer 的宽度,高度,像素格式和使用标志,从 BufferQueue 请求释放 Buffer
生产者(Producer) 将填充缓冲区,并通过调用 queueBuffer()将缓冲区返回到队列。
消费者(Consumer) 使用 acquireBuffer()获取 Buffer 并消费 Buffer 的内容
使用完成后,消费者(Consumer)将通过调用 releaseBuffer()将 Buffer 返回到队列
在 Android App 的渲染流程里面,App 就是个生产者(Producer) ,而 SurfaceFlinger 是一个消费者(Consumer),所以上面的流程就可以翻译为
当 App 需要 Buffer 时,它通过调用 dequeueBuffer()并指定 Buffer 的宽度,高度,像素格式和使用标志,从 BufferQueue 请求释放 Buffer
App 可以用 cpu 进行渲染也可以调用用 gpu 来进行渲染,渲染完成后,通过调用 queueBuffer()将缓冲区返回到 App 对应的 BufferQueue(如果是 gpu 渲染的话,这里还有个 gpu 处理的过程)
SurfaceFlinger 在收到 Vsync 信号之后,开始准备合成,使用 acquireBuffer()获取 App 对应的 BufferQueue 中的 Buffer 并进行合成操作
合成结束后,SurfaceFlinger 将通过调用 releaseBuffer()将 Buffer 返回到 App 对应的 BufferQueue
单缓存
单 Buffer 情况,因为只有一个 Buffer 可用,这个 Buffer 既要用来做合成显示,又要被应用拿去做渲染。
理想情况下,单 Buffer 也是可以完成任务不卡顿丢帧的。
1、App 收到 Vsync 信号,获取 Buffer 开始渲染;
2、间隔 Vsync-Offset 时间后,SurfaceFlinger 收到 Vsync 信号,开始合成;
3、屏幕刷新,我们看到合成后的画面。
但很不幸,理想情况也就想一想,任何一个环节,如果 App 渲染或者 SurfaceFlinger 合成,在屏幕显示刷新之前还没完成,那么屏幕刷新时候,拿到的 Buffer 就是不完整的,用户看来,就有撕裂的视觉效果。
双缓冲
两个缓存区: Back Buffer 、 Frame Buffer。当写入下一帧时,GPU会先填充 Back Buffer 中,当刷新屏幕时,屏幕从 Frame Buffer 中读数据。VSYNC 主要是完成帧的复制,开始下一帧的渲染。
Choreographer主要是配合 Vsync ,给上层 App 的渲染提供稳定的 Message 处理的时机,Vsync 到来时候 ,系统通过对 Vsync 信号周期的调整,控制每1帧绘制时机。Vsync 周期如果是 16.6ms (60 fps) ,是因为手机屏幕是 60Hz 的刷新率,也就是 16.6ms 刷新1次,系统为了配合屏幕刷新频率,将 Vsync 的周期也设置为 16.6 ms,每隔 16.6 ms ,Vsync 信号到来唤醒 Choreographer 来做 App 的绘制操作 ,如果每个 Vsync 周期应用都能渲染完成,那么应用的 fps 就是 60 ,用户的感觉就是非常流畅,这就是引入 Choreographer 的主要作用。
Android双Buffer与三Buffer丢帧卡顿对比
双buffer下,主线程连续超时,开始丢帧。三buffer减轻丢帧情况,从原先丢2帧减轻到丢1帧。
主线程有时要等待 SurfaceFlinger释放Buffer后,才能获取 Buffer 进行生产,但大部分情况下, SurfaceFlinger 和应用主线程 同时收到 Vsync 信号,如果应用主线程等待SurfaceFlinger释放 Buffer,那会让应用主线程执行时间延后。
双 Buffer 时候,App生产的 Buffer 必须要及时拿去让 GPU 渲染,然后 SurfaceFlinger 才能进行合成,一旦 GPU 超时,就容易出现 SurfaceFlinger 无法及时合成而导致掉帧;在三 Buffer 轮转时候,App 生产的 Buffer 可及早进入 BufferQueue,让 GPU 去进行渲染(因为不需等待),当 SurfaceFlinger 本身负载比较大,三个 Buffer 轮转也会有效降低 dequeueBuffer 等待时间。
App 与 SurfaceFlinger 的交互主要集中在三点
- Vsync 信号的接收和处理
- RenderThread 的 dequeueBuffer
- RenderThread 的 queueBuffer
RenderThread 的 dequeueBuffer
dequeue 有出队的意思,dequeueBuffer 顾名思义,就是从队列中拿出一个 Buffer,这个队列就是 SurfaceFlinger 中的 BufferQueue。如下图,应用开始渲染前,首先需要通过 Binder 调用从 SurfaceFlinger 的 BufferQueue 中获取一个 Buffer。
- dequeue(生产者发起) : 当生产者需要缓冲区时,它会通过调用 dequeueBuffer() 从 BufferQueue 请求一个可用的缓冲区,并指定缓冲区的宽度、高度、像素格式和使用标记。
- queue(生产者发起):生产者填充缓冲区并通过调用 queueBuffer() 将缓冲区返回到队列。
- acquire(消费者发起) :消费者通过 acquireBuffer() 获取该缓冲区并使用该缓冲区的内容
- release(消费者发起) :当消费者操作完成后,它会通过调用 releaseBuffer() 将该缓冲区返回到队列
当 VSYNC 信号到达时,SurfaceFlinger 会遍历它的层列表,以寻找新的缓冲区。如果找到新的缓冲区,它会获取该缓冲区;否则,它会继续使用以前获取的缓冲区。SurfaceFlinger 必须始终显示内容,因此它会保留一个缓冲区。如果在某个层上没有提交缓冲区,则该层会被忽略。SurfaceFlinger 在收集可见层的所有缓冲区之后,便会询问 Hardware Composer 应如何进行合成。
这里丢帧了(Jank),丢1帧:
从SurfaceFlinger端才能真正认定丢帧:
Android性能分析:卡顿丢帧基础CPU/GPU原理(4)-CSDN博客文章浏览阅读821次,点赞18次,收藏19次。产生 Jank 的那一帧的显示期间,GPU/CPU 在闲置的。CPU返回后,会直接将GraphicBuffer提交给SurfaceFlinger,告诉SurfaceFlinger进行合成,但是这个时候GPU可能并未完成之前的图像渲染,这时候就牵扯到一个同步,Android中,用的是Fence机制,SurfaceFlinger合成前会查询Fence,如果GPU渲染没有结束,则等待GPU渲染结束,GPU结束后,会通知SurfaceFlinger进行合成,SF合成后,提交显示,最终完成图像的渲染显示。https://blog.csdn.net/zhangphil/article/details/138804486
Android GPU渲染屏幕绘制显示基础概念(1)-CSDN博客文章浏览阅读1k次,点赞30次,收藏18次。CPU返回后,会直接将GraphicBuffer提交给SurfaceFlinger,告诉SurfaceFlinger进行合成,但是这个时候GPU可能并未完成之前的图像渲染,这时候就牵扯到一个同步,Android中,用的是Fence机制,SurfaceFlinger合成前会查询Fence,如果GPU渲染没有结束,则等待GPU渲染结束,GPU结束后,会通知SurfaceFlinger进行合成,SF合成后,提交显示,最终完成图像的渲染显示。而对SF来说,只要有合成任务,它就得再去申请VSYNC-sf。https://blog.csdn.net/zhangphil/article/details/138585120Android GPU渲染SurfaceFlinger合成RenderThread的dequeueBuffer/queueBuffer与fence机制(2)-CSDN博客文章浏览阅读794次,点赞12次,收藏17次。t 时长,20s,20秒的trace文件。CPU返回后,会直接将GraphicBuffer提交给SurfaceFlinger,告诉SurfaceFlinger进行合成,但是这个时候GPU可能并未完成之前的图像渲染,这时候就牵扯到一个同步,Android中,用的是Fence机制,SurfaceFlinger合成前会查询Fence,如果GPU渲染没有结束,则等待GPU渲染结束,GPU结束后,会通知SurfaceFlinger进行合成,SF合成后,提交显示,最终完成图像的渲染显示。就是 Buffer。https://blog.csdn.net/zhangphil/article/details/138628225Android性能:SurfaceFlinger与BufferQueue(3)-CSDN博客文章浏览阅读757次,点赞25次,收藏24次。t 时长,20s,20秒的trace文件。CPU返回后,会直接将GraphicBuffer提交给SurfaceFlinger,告诉SurfaceFlinger进行合成,但是这个时候GPU可能并未完成之前的图像渲染,这时候就牵扯到一个同步,Android中,用的是Fence机制,SurfaceFlinger合成前会查询Fence,如果GPU渲染没有结束,则等待GPU渲染结束,GPU结束后,会通知SurfaceFlinger进行合成,SF合成后,提交显示,最终完成图像的渲染显示。就是 Buffer。https://blog.csdn.net/zhangphil/article/details/138631517
Android性能:Double Buffer双缓冲/Triple Buffer三缓冲丢帧Jank与无丢帧No Jank-CSDN博客文章浏览阅读842次,点赞6次,收藏13次。Android ADB调试真机设备Android ADB(Andorid Debug Bridge),是Android开发中有用的测试和调试工具。使用Android ADB调试设备,直接在Windows的dos命令窗口输入命名adb即可,如图:为什么执行adb命令后是这样?_android 抓trace。三Buffer轮转情况下,基本不会有这种情况的发生,渲染线程一般在 dequeueBuffer 时,都可以顺利拿到可用的 Buffer (如果 dequeueBuffer 本身耗时那就也会拉长时间)。https://zhangphil.blog.csdn.net/article/details/138213964
Android硬件加速hardwareAccelerated支持/不支持的绘图接口-CSDN博客文章浏览阅读262次,点赞3次,收藏14次。三Buffer轮转情况下,基本不会有这种情况的发生,渲染线程一般在 dequeueBuffer 时,都可以顺利拿到可用的 Buffer (如果 dequeueBuffer 本身耗时那就也会拉长时间)。在Android早期的版本,由于硬件制造商差异大,增加了这一开关,但随着Android系统版本的迭代,以及硬件技术水平提升,现有的绝大多数Android手机硬件层面均已支持硬件加速(GPU渲染),Android本身也只有有限几个接口不支持硬件加速。https://blog.csdn.net/zhangphil/article/details/138502494
Android adb shell命令捕获systemtrace_android 抓trace-CSDN博客文章浏览阅读1.7k次,点赞2次,收藏5次。Android ADB调试真机设备Android ADB(Andorid Debug Bridge),是Android开发中有用的测试和调试工具。使用Android ADB调试设备,直接在Windows的dos命令窗口输入命名adb即可,如图:为什么执行adb命令后是这样?Android ADB(Andorid Debug Bridge)调试真机设备_adb在线执行器_zhangphil的博客-CSDN博客。-t 时长,20s,20秒的trace文件。-o 保存文件路径。_android 抓tracehttps://blog.csdn.net/zhangphil/article/details/131249820
adb shell top -m 10 -s 1 -d 1 -o %CPU,%MEM,TIME+,PID,COMMAND,CMDLINE_adb shell top -m 10 -s cpu-CSDN博客文章浏览阅读390次。使用Android ADB调试设备,直接在Windows的dos命令窗口输入命名adb即可,如图:为什么执行adb命令后是这样?Android ADB(Andorid Debug Bridge)调试真机设备_adb在线执行器_zhangphil的博客-CSDN博客。Android adb shell dump当前手机设备的所有activity_dump当前activity_zhangphil的博客-CSDN博客。Android adb获取CPU信息_zhangphil的博客-CSDN博客。_adb shell top -m 10 -s cpuhttps://blog.csdn.net/zhangphil/article/details/131412814