安卓图形显示系统

图形显示系统架构

总的来说,整个安卓显示系统是由两组生产者–消费者解构组成的:

1. surface(Producer)<-> surfaceflinger(Consumer)

其中两者的控制交互采用binder机制,因为surface属于各个应用充当的client进程端,而surfaceflinger为单独进程。另外,图形数据采用BufferQueue(实际为共享内存)进行关联,如下图
在这里插入图片描述

  • Dequeued:出列,正在被上层使用
  • Queued:入列,已完成上层绘制,等待SurfaceFlinger合成
  • Acquired:被获取,SurfaceFlinger正持有该Buffer进行合成
  • Free:SurfaceFlinger使用完毕,可被上层使用

2. surfaceflinger(Producer)<-> screen(Consumer)

surfaceflingerHWC2进程的协助下,合成完各layer后,会送往“DRM”(LINUX
中用以替代framebuffer的显示驱动模块)模块进行送显,此时surfaceflinger充当生产者角色,它与消费者采用硬件的 double buffer(或者为Triple buffer)进行数据传递
在这里插入图片描述

上图中,CPU\GPU节点代表应用的绘图过程,Composite则代表surfaceflinger的合成过程,当然合成分为两种形式:

  • Client合成
    Client合成方式是相对与硬件合成来说的,其合成方式是,将各个Layer的内容用GPU渲染到暂存缓冲区中,最后将暂存缓冲区传送到显示硬件。这个暂存缓冲区,我们称为FBTarget,每个Display设备有各自的FBTarget。Client合成,之前称为GLES合成或者GPU合成,总之这种方式中HWC无专门硬件处理。
  • Device合成
    就是用专门的硬件合成器进行合成,所以硬件合成的能力就取决于硬件的实现。其合成方式是将各个Layer的数据全部传给显示硬件,并告知它从不同的缓冲区读取屏幕不同部分的数据。HWComposer是Devicehec的抽象。

3. surface、surfaceflinger、 screen同步机制

上节提到两组生产消费者的关系。其中屏幕与surfaceflinger之间最开始时基于vsync(屏幕刷新中断,硬件或者软件模拟)触发的,即屏幕完成一次刷新后,送出Vsync中断,切换前后帧用以显示下一帧。但是仔细观察这个过程会发现,屏幕仅与surfaceflinger实现同步是不够的,毕竟一副图像产生的源头是各个surface(也就是CPU\GPU的绘制),考虑如下两种情况:
在这里插入图片描述
当前屏幕显示第0帧,上层CPU开始计算第1帧的纹理,计算完成后,交由GPU进行栅格化。当下一个垂直同步信号到来,屏幕显示下一帧,这时候,上层CPU并未马上开始准备下一帧,而当CPU开始准备下一帧的时候已经太晚了,下一个VSync信号来临的时候,GPU未能绘制完第二帧的处理,导致屏幕再次显示上一帧,造成卡顿。所以说,vsync不仅要完成硬件前后buffer切换,还需要统筹cpu来同步绘图的步调,因此vsync同步信号被传递到了上层使用,这就是Android 4.1之后引入的垂直同步技术(其实就是显卡大厂们提出的vsync垂直同步技术):
在这里插入图片描述
为了将vsync给到上层,Android设计了一个Choreographer 类,该类可以将Framework收到的的vsync中断通过异步消息发送的应用中的消息队列,应用在未接收vsync时是被阻塞的,只有接收到vsyn信号才会执行下一帧的绘制,流程如下:
在这里插入图片描述
通过将vsync运用到上层理论上可以确保应用在最合适的时间去绘制下一帧图像,理想的情况应该是:
在这里插入图片描述
但是,CPU毕竟要干很多活,所以即便在“最合适的”时间启动绘制,也不能保证在“规定的”时间完成绘制:
在这里插入图片描述
上图中,按理说第三张图像应该在第一个vsync时开始绘制,但实际第二张图像还没有完成,导致buffer不够用,所以只能在下一个vsync时启动,并且当前刷新周期也只能继续显示第一幅图像,此时依然会造成卡顿。同时下一个vsync内,由于cpu启动绘图实际比较晚,所以留给gpu的时间偏少,极易导致卡顿再次出现
上述情况发生的根因在于一个vsync周期内,CPU与GPU只能轮换使用同一块buffer,因此两者只能串行去做。怎么办呢?增加一块buffer!
在这里插入图片描述
三块缓冲区时,CPU与GPU可以同时工作,但是第一次卡顿无法消除,这是因为GPU自身的原子操作必须完成才会刷新到屏幕上,这个通过增加buffer是无效的。但是增加第三块buffer可以让cpu在下一个vsync是尽早开始绘图,那么留给GPU时间相对会多一下,这样可避免连续的卡顿出现。所以新版的安卓系统,卡顿现象变得轻了一些… 另外对于应用开发者而言,降低CPU或者GPU的负荷是优化顿更少出现的唯一手段。

4. 显示系统框图

目前为止,java部分并未展开学习,但是整个framework有关显示的部分已经可以画出简单的框图了:
在这里插入图片描述在这里插入图片描述

  • 上图描述了SurfaceFlinger和BufferQueue的流程,在帧期间During frame:

    1. 红色缓冲区填充,滑动到BufferQueue

    2. 当红色缓冲区离开应用后,蓝色缓冲区滑入,替代红色缓冲区

    3. 绿色缓冲区 以及阴影所示系统UI 滑入 HWC(图上SurfaceFlinger仍然有这些缓冲区,但是现在HWC 已经准备将他们用于下一个VSYNC到达的显示,通过overlay).

      系统UI进程提供了状态条和导航条,为简化起见 这些layer没有改动。因此,SurfaceFlinger仍继续使用之前获取的缓冲区。
      
  • 蓝色缓冲区 由Display和BufferQueue同时引用,应用目前还不容需将其用于渲染,直到对应的同步fence发出信号。

  • 在VSYNC到达是,下列操作同时发生:

  1. 红缓冲区 跳入 SurfaceFlinger,替代了绿色缓冲区
  2. 绿缓冲区跳入 Display,替代了蓝色缓冲区。a dotted-line green twin appears in the BufferQueue绿色虚线的双胞胎(twin) 出现在BufferQueue。
  3. 蓝色缓冲区的fence 发出信号,系统中的蓝色缓冲区清空。
    这里的缓冲区并没有实际清空;如果你没有绘制就提交,你讲得到同样的蓝色的内容。清空 实际上是清除缓冲区的内容,应用应该在开始绘制之前做清除工作。
  4. 显示区域由 《blue+systemUI 》变为 《green+systemUI》

对于其中的关键服务或者技术,例如:HWC(Overlayer)、SurfaceFlinger、BufferQueue、Surface、View等只能一个一个的去展开学习,毕竟内容非常庞大。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值