Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

【图形图像】Android SurfaceFlinger之VSync

$
0
0

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。

……

作者:iEearth 发表于2017/3/17 21:02:03 原文链接
阅读:165 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles