页面绘制的来龙去脉

程序员小迷 2024-08-10 11:04:31

一、概述

1.Android 中,用户编写的应用程序(Client)测量和计算布局,SurfaceFlinger(Server)用来渲染绘制界面,Client和Server通过匿名共享内存(Anonymous Shared Memory)通信。

2.每个应用和 SurfaceFlinger 之间都会创建一个SharedClient,一个 SharedClient 最多可以创建31 个 SharedBufferStack,每个 Surface 对应一个 SharedBufferStack,也就是一个 Window。即每个应用最多可以创建 31 个窗口。

二、原理

1.Android 4.1 之后,Android OS 团队对 Android Display 进行了进化和改变,引入了三个核心元素:Vsync,Triple Butter,Choreographer。

2.图形界面的绘制,是由 CPU 准备数据,然后通过驱动层把数据交给 GPU 进行绘制。图形 API 不允许 CPU 和 GPU直接通信,所以就有了图形驱动(Graphics Driver)来进行通信。图形驱动 维护了一个序列(Display List),CPU 不断把需要显示的数据放进去,GPU 不断地将数据取出来进行显示。其中 Choreographer 起调度的作用,统一绘制图像到 Vsync 的某个时间点。

Choreographer在收到Vsync信号时,调用用户设置的回调函数。函数的先后顺序如下:

1)CALLBACK_INPUT:与输入事件有关

2)CALLBACK_ANIMATION:与动画有关

3)CALLBACK_TRAVERSAL:与 UI 绘制有关

3.Android中开发者可以通过SurfaceHolder来访问和操作缓冲区,在绘制每一帧之前调用lockCanvas()来获取缓冲区,并在绘制完成后调用unlockCanvasAndPost()来提交更改。

三、多重缓冲

1.概述

1)多重缓冲允许程序在后台缓冲区准备数据,在前台缓冲区显示页面,从而避免了在更新数据时造成的屏幕闪烁或卡顿。

2)OpenGL ES、Android Canvas绘制和视频播放时为避免等待数据时的卡顿,也会使用多重缓冲。

2.双重缓冲

在 Linux 上,通常使用 FrameBuffer 来做显示输出。

双重缓冲会创建一个 FrontBuffer 和一个 BackBuffer,FrontBuffer 是当前显示的页面,BackBuffer是下一个要显示的画面。然后前后缓存依次交替显示数据。

这样的特点为:

1)如果是单重缓冲,页面可能会有这种情况:A 数据需要显示,然后是 B 数据显示,B 数据显示需要耗费一定时间,但是这个时间里,C 数据也请求了展示,我们可能会看到,在展示 C 数据的时候,还有 B 数据的残影。而双重缓冲会更好得避免这个问题。

2)双重缓冲仍然可能会卡。

3)CPU 和 GPU 的刷新时间,和Display的FPS是一致的。因为只有到发出 Vsync 命令的时候,CPU 和GPU才会进行刷新或显示的动作。

3.三重缓冲

1)在渲染过程中,一个缓冲区用于显示,一个用于渲染,一个用于备用。当渲染完成时,备用缓冲区变为渲染缓冲区,渲染缓冲区变为显示缓冲区,原来的显示缓冲区变为备用缓冲区。

2)除了 A 和 B 两个图层在交替显示,还有一个第三者 C 图层在不断帮A和B可能需要展示的数据进行缓冲。实际中只有在需要时,才会进行三重缓冲。正常情况下,只使用二重缓冲。

2)缓冲区不是越多越好。

4.当GPU的帧率高于显示器的刷新率时,可能出现一个刷新周期内GPU生成多帧数据的情况,从而造成画面撕裂。为解决这一问题,使用多重缓冲来同步GPU帧率和显示器刷新率。

微风不燥,阳光正好,你就像风一样经过这里,愿你停留的片刻温暖舒心。

我是程序员小迷(致力于C、C++、Java、Kotlin、Android、iOS、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享),若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢,您的支持是我们为您提供帮助的最大动力。

欢迎关注。助您在编程路上越走越好!

0 阅读:8

程序员小迷

简介:致力于Android、iOS、C、Java等编程技术的技巧经验分享