vsync简单理解就是一帧图像在显示设备这边显示完成之后(图像从左上角扫描到了右下角了) 发送的第一个硬件vsync信号, 显示设备重新回到左上角开始显示的时候会在发第二个vsync信号。在发送第一个vsync信号出来的时候,上层要开始准备合成处理好的图像buffer。而且这个必须在下一个vsync到达之前准备完成 否则显示会出现异常。 vsync 信号主要应用app刷新,视频显示刷新。
问题:
网上资料,有些太旧运行不了,最好的参考的代码是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 从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());
}
}
构造函数流程:
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;
}
}
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