深入Android系统(十二)Android图形显示系统-1-显示原理与Surface

本文深入探讨Android图形显示系统,解释VSYNC信号在防止画面闪烁中的作用,以及Surface如何作为显示内容的容器。文章介绍了Surface的创建过程,包括从应用到SurfaceFlinger的层层传递,详细剖析了Surface与SurfaceFlinger、SurfaceView、ViewRootImpl等组件的关系,揭示了Android系统如何确保图形渲染的流畅性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • Window Positioning中的WindowManager主要是用来控制Window对象

  • Window对象是用来存放View对象的容器,每个Window对象都会关联Surface对象

  • WindowManager监视Window对象的生命周期、输入和焦点事件、屏幕方向、转换、动画、位置、变换、z顺序等

  • 然后将所有Window元数据发送给SurfaceFlingerSurfaceFlinger利用这些元数据把自己管理的所有Surface组合成layer

  • 然后交给Hardware Composer做进一步处理

  • HAL层中的Hardware Composer(HWC)会根据当前硬件来进一步进行缓冲区的组合,它的具体实现依赖于特定的显示设备

  • 官网关于HWC的数据流如下:

image

  • SurfaceFlinger作为clientHWC提供一个完整的layer列表,然后询问HWC计划如何处理
  • HWC会将这些layer标记为client合成或者device合成并告知SurfaceFlinger
  • SurfaceFlinger将处理标记为client合成layer,然后通过BufferQueue传递给HWC
  • 余下的layerHWC自行处理

网上一篇很有趣的渲染总结(文中有些错误,但瑕不掩瑜):Android渲染原理

VSYNC信号

前面提到Linux使用Framebuffer来用作显示输出。但是,如果在屏幕更新到一半时,用户进程更新了Framebuffer中的数据,将导致屏幕上画面的上半部分是前一帧的画面,下半部分变成了新的画面。当然这种异常会在下次刷新时纠正过来,但是在用户感知上画面会出现闪烁感

  • 针对这种情况,早期的解决方法是使用双缓冲机制,双缓冲就是提供两块Framebuffer,一块用于显示,另一块用于数据更新,数据准备好后,通过ioctl操作告诉显示设备切换用于显示的Framebuffer,这样图像就能快速的显示出来了
  • 但是双缓冲并没有完全解决问题,虽然双缓冲切换的速度很快,但是如果切换的时间点不对,在画面更新一半的时候进行切换,还是会出现单缓冲区遇到的闪烁问题
  • 当然,可以在底层进行控制,当收到切换请求后内部并不马上执行,而是等到刷新完成后再切换,这样可以完全避免画面重叠的问题
  • 但是,这样做会带来新的问题,如果ioctl操作完成后缓冲区没有切换,应用就不能确定何时可以再使用缓存区,只能通过ioctl不停地查询缓冲区状态,直到切换完成。这种CPU主动查询的方式很低效

为此Android让底层固定地发送信号给用户进程,通知进程切换的时机,这样就避免了用户进程主动查询的操作。而这个信号就是VSYNC信号

官方传送门:VSYNC

官方描述如下:VSYNC信号用来同步整个显示流程(Display Pipeline)显示流程包括app渲染、SurfaceFlinger合成、HWC(硬件渲染)组成

(这部分感觉原文更容易理解)VSYNC synchronizes the time apps wake up to start rendering, the time SurfaceFlinger wakes up to composite the screen, and the display refresh cycle.

VSYNC信号应该由显示驱动产生,这样才能达到最佳效果。但是Android为了能运行在不支持VSYNC机制的设备上,也提供了用软件来模拟产生VSYNC信号的手段

官网描述:通过HWC来产生VSYNC信号,并通过接口回调将事件进行发送(主要是SurfaceFlinger进行事件接收)

基础知识铺垫完成,我们先来看看Surface

Surface

官网对Surface的描述是:A surface is an interface for a producer to exchange buffers with a consumer.

上面描述的是一种生产者-消费者的模式,而Surface充当了中间衔接的角色。

ActivityUI显示为例:

  • 生产者的任务就是把图形绘制在Surface对象上

  • 比较出名的生产者就是SurfaceView组件了

  • SurfaceFlinger作为消费者会把所有Surface对应的图像层混合在一起

  • 最后消费者将其输出到FrameBuffer中,这样在屏幕上就看到最后合成的图像了

下面我们从Java层开始分析Surface

应用中Surface的创建过程

应用开发中很少直接使用Surface,因为每个Activity中都已经创建好了各自的Surface对象,通常只有一些特殊的应用才需要在Activity之外再去创建Surface,例如相机、视频播放应用。

不过,通常这些应用也是通过创建SurfaceView来使用Surface

需要注意的是,在应用中不能直接去创建一个可用的Surface对象(也可以说直接创建出的对象没什么实际用途),因为这样创建出的Surface对象和SurfaceFlinger之间没有任何关联。

该如何创见一个可用的Surface对象呢?
我们看下Surface类的定义:

public class Surface implements Parcelable {
long mNativeObject;
// 一个无参构造,空实现
public Surface() {
}
public Surface(SurfaceTexture surfaceTexture) {
if (surfaceTexture == null) {
throw new IllegalArgumentException(“surfaceTexture must not be null”);
}
mIsSingleBuffered = surfaceTexture.isSingleBuffered();
synchronized (mLock) {
mName = surfaceTexture.toString();
setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
}
}
}

Surface类对外有两个构造方法:

  • 一个是无参构造,实现也是空的

  • 注释中说这个主要是给readFromParcel()反序列化用的

  • 那我们看下readFromParcel()方法

public void readFromParcel(Parcel source) {
if (source == null) {
throw new IllegalArgumentException(“source must not be null”);
}
synchronized (mLock) {
mName = source.readString();
mIsSingleBuffered = source.readInt() != 0;
setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
}
}

  • 另一个需要传递SurfaceTextur

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值