Android 显示surfaceFlinger vsync 获取

文章目录

      • vsync 的概念
      • vsync应用层获取的方式
      • vsync 信号传递

vsync 的概念

vsync简单理解就是一帧图像在显示设备这边显示完成之后(图像从左上角扫描到了右下角了) 发送的第一个硬件vsync信号, 显示设备重新回到左上角开始显示的时候会在发第二个vsync信号。在发送第一个vsync信号出来的时候,上层要开始准备合成处理好的图像buffer。而且这个必须在下一个vsync到达之前准备完成 否则显示会出现异常。 vsync 信号主要应用app刷新,视频显示刷新。

问题:

  1. vsync信号是硬件发出的,那上层应该怎么去获取?
  2. vsync 如何从底层传递到应用?

vsync应用层获取的方式

网上资料,有些太旧运行不了,最好的参考的代码是google的源码的test。

  • google 参考方法

    源码位置:frameworks\native\services\surfaceflinger\tests\vsync\vsync.cpp

简要流程:硬件的vsync抽象在上层是一个fd。当有vsync的时候,上层looper会调用receiver 回调,在回调中就可以获取到count 和timestamp。回调函数必须是 下面三个参数这样的。

int receiver(int /*fd*/, int /*events*/, void* data)

addFd 将displayEvent的fd、要添加的事件也即有事件输入,有事件之后的回调函数,disPlayEvent自身(用于传递到回调函数获取)

实现时需要创建一个线程,在线程中队DisplayEventReceiver的fd进行pollOnce 操作。
fd没有poll_input的消息时,线程会堵塞。会消息的时候pooll返回 然后调用回调函数receiver,在receriver可以获取vysnc的count和timestamp。

    DisplayEventReceiver myDisplayEvent;
    sp loop = new Looper(false);
    loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver, &myDisplayEvent);

int receiver(int /*fd*/, int /*events*/, void* data) {
    DisplayEventReceiver* q = (DisplayEventReceiver*)data;
    ssize_t n;
    DisplayEventReceiver::Event buffer[1];
    static nsecs_t oldTimeStamp = 0;
    while ((n = q->getEvents(buffer, 1)) > 0) {
        for (int i = 0; i < n; i++) {
            ALOGD("buffer[i].header.type is :%d \n", buffer[i].header.type);
            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
                ALOGD("event vsync: count=%d\t", buffer[i].vsync.count);
            }
            if (oldTimeStamp) {
                float t = float(buffer[i].header.timestamp - oldTimeStamp) / s2ns(1);
                ALOGD("%f ms (%f Hz)\n", t * 1000, 1.0 / t);
            }
            oldTimeStamp = buffer[i].header.timestamp;
        }
    }
    return 1;
}

vsync 信号传递

vsync 从hwc 获取到之后 回调到surfaceflinger, surfaceFlinger 通过socket发送到应用。

  • 应用注册fd到surfacefinger流程

    主要在DisplayEventReceiver构造函数中实现。

    sp sf(ComposerService::getComposerService());
    if (sf != nullptr) {
        mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
        if (mEventConnection != nullptr) {
            mDataChannel = std::make_unique();
            mEventConnection->stealReceiveChannel(mDataChannel.get());
        }
    }

构造函数流程:

  1. 获取surfaceflinger的服务。
  2. 通过surfaceflinger的createDisplayEventConnection的函数创建一个gui::BitTube对象,
    gui::BitTube管理一对无名的socket, 这个socket会对BitTube的mReceived 和 mSendFd
    进行初始化。
  3. 应用端也会创建一个gui::BitTube,并传递到surfaceflinger中,surfaceflinger 中将已经创建好的BitTube中mReceived赋值给外部创建好BitTube中的mReceived。
    这样外部应用端和surfaceFlinger建立了连续。发送到surfaceflinger BitTube的mSendFd的消息,应用端可以监听并接收。

DisplayEventDispatcher继承自LooperCallback,看LooperCallback的实现可以知道addFd
的有INPUT的event后回调到的是handleEvent。

class DisplayEventDispatcher : public LooperCallback

    if (mLooper != nullptr) {
        int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
        if (rc < 0) {
            return UNKNOWN_ERROR;
        }
    }

  • surfaceFlinger 注册vsync回调到hwc以及 回调上报的路径
  1. 首先hwc是一个hal层的服务 其接口定义在这个目录 hardware/interfaces/graphics/composer/2.1。其对应的service 是[email protected]。 surfaceflinger提供这个composer的service提供的接口 可以注册回调到hwcomposer 的hal层中。
mCompositionEngine->getHwComposer().setCallback(this);

 mComposer->registerCallback(
            sp::make(callback, mComposer->isVsyncPeriodSwitchSupported()));


void Composer::registerCallback(const sp& callback)
{
    android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);
    auto ret = [&]() {
        if (mClient_2_4) {
            return mClient_2_4->registerCallback_2_4(callback);
        }
        return mClient->registerCallback(callback);
    }();
    if (!ret.isOk()) {
        ALOGE("failed to register IComposerCallback");
    }
}

而在hal层的 vsync的实现各不相同。 有一种实现方式运行一个线程,然后在线程中使用
drmWaitVBlank等待vsync,vsync产生后回调到之前surfaceflinger 注册进来的callback中。

在surfaceflinger中会创建一个DispSyncThread线程,这个线程收到vsync事件后也就是回调到onComposerHalVsync中时。通过之前注册进来的EventThread的callback
构造了一个DisplayEventReceiver::Event类型事件,类型为DISPLAY_EVENT_VSYNC,还有displayId,时间戳以及接收到的次数。构造好之后会唤醒EventThread线程,这个线程从mPendingEvents中的事件调用dispatchEvent将事件分发给监听者,监听者即是向EventThread请求了Vsync的EventThreadConnection并addfd的配置回调函数的。

void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp,
                                        std::optional vsyncPeriod)
    mScheduler->addResyncSample(timestamp, vsyncPeriod, &periodFlushed);

参考链接:
https://blog.csdn.net/qq_34211365/article/details/105123790

你可能感兴趣的:(android,音视频,surfaceflinger,vsync)