1、VSync简介
在Android GUI系统的多缓冲机制中,一个关键性的角色是VSync,充分利用了CPU/GPU与Display的交互机制,让UI表现更流畅。VSync即Vertical Sync,因为Display是逐行扫描的,从上到下,当扫描到最后一行时便返回第一行进行下一轮扫描,从最后一行返回到第一行有一段时间间隔,此时发出一个VSync信号,通知系统进行swap buffer(认为这个时间点swap buffer性能最佳),那么什么是swap buffer呢?swap buffer源于有多个buffer,如果只有一个buffer也就不用swap buffer了。
当只有一个buffer时,首先由CPU/GPU准备好一帧数据写入buffer,然后Display读取buffer并刷新显示buffer中的内容,这里有一个问题,如果CPU/GPU的帧率即fps比Display的刷新频率快的话,新一帧的数据会覆盖旧一帧的数据,导致画面扭曲;于是引入了两个buffer,一个frame buffer即screen buffer,专门用于Display显示,一个backup buffer即off-screen buffer,专门用于CPU/GPU渲染,所以需要swap buffer更新frame buffer中的内容,那么什么时候swap buffer呢?这时就用到了VSync,VSync信号到来时,进行swap buffer并通知CPU/GPU准备下一帧数据,如果没有VSync,CPU/GPU很有可能处于闲置状态,没能即时准备下一帧数据,造成资源浪费;但是VSync也带来了另一个问题,因为保证CPU/GPU帧率与Display刷新频率一致,实际的CPU/GPU帧率将不得超过Display刷新频率,同时如果VSync信号到来时,off-screen buffer还没有完成则不进行swap buffer,Display显示的是前面一帧的数据,出现掉帧现象,而且GPU工作时CPU闲置,fps大幅度下降,所以又引入了三个buffer,第三个buffer在需要时才创建,用以CPU即时渲染,提高fps。
2、VSync与SurfaceFlinger
在Android系统中,VSync信号可以由硬件触发,也可以由软件模拟,其源码位置在frameworks/native/services/surfaceflinger/DisplayHardware,属于SurfaceFlinger中的内容,在最新的Android 7中,与VSync相关的Hardware Composer已从1.x升级为2.0,使用了大量的C++11,且保留了1.x版本,下面介绍HWC 2.0中的VSync机制。
首先,在HWComposer构造函数中,通过如下的loadHwcModule加载HWC模块,而HWComposer对象在surfaceflinger启动过程中由SurfaceFlinger对象进行初始化时构建。
// 加载Hardware Composer模块
void HWComposer::loadHwcModule()
{
// 1
// dlopen/dlsym hwcomposer库
// #define HWC_HARDWARE_MODULE_ID "hwcomposer"
hw_module_t const* module;
if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
abort();
}
// 2
// open composer设备然后mmap对应的fd
// #define HWC_HARDWARE_COMPOSER "composer"
hw_device_t* device = nullptr;
int error = module->methods->open(module, HWC_HARDWARE_COMPOSER, &device);
if (error != 0) {
abort();
}
// 3
// 根据Hardware Composer版本信息设置Device
// 这里使用了c++11
uint32_t majorVersion = (device->version >> 24) & 0xF;
if (majorVersion == 2) {
mHwcDevice = std::make_unique<HWC2::Device>(
reinterpret_cast<hwc2_device_t*>(device));
} else {
mAdapter = std::make_unique<HWC2On1Adapter>(
reinterpret_cast<hwc_composer_device_1_t*>(device));
uint8_t minorVersion = mAdapter->getHwc1MinorVersion();
if (minorVersion < 1) {
ALOGE("Cannot adapt to HWC version %d.%d",
static_cast<int32_t>((minorVersion >> 8) & 0xF),
static_cast<int32_t>(minorVersion & 0xF));
abort();
}
mHwcDevice = std::make_unique<HWC2::Device>(
static_cast<hwc2_device_t*>(mAdapter.get()));
}
mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
}
加载HWC模块,说白了就是处理对应的so,这个so对应的源码位置在hardware/libhardware/modules/hwcomposer,从这里的Android.mk可以看出这是个默认的HWC模块,为hwcomposer.default,也就是说我们可以定制其它的HWC实现。
在VSync的整个实现机制中,有几个概念非常重要:event/message处理、callback、多线程与同步,这些在整个Android系统的各模块中用法类似。例如,对于多线程来说,包括用于Display同步的DispSyncThread,HWC 1.x版本中用于模拟VSync信号的VSyncThread,用于控制整个SurfaceFlinger事件的核心线程EventControlThread以及基本线程EventThread。
……