app Vsync 的请求、定时、回调和结束
一、app 请求Vsync
app vsync关键的类是EventThread.cpp,在其构造函数里面会开启一个线程在threadMain()函数里面进行循环。当app进程通过binder跨进程请求vsync信号的时候会调EventThread::requestNextVsync()函数。
1、app vsync 的请求
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {std::lock_guard<std::mutex> lock(mMutex);。。。。。if (connection->vsyncRequest == VSyncRequest::None) {connection->vsyncRequest = VSyncRequest::Single;mCondition.notify_all();} 。。。。。
}
这里会将connection->vsyncRequest设置为 VSyncRequest::Single,并唤醒threadMain里面的等待。
VSyncRequest分为三中类型,分别为
None:表示不在进行vsync的定时。
Single:app有vsync请求的时候是这个状态,接下来需要想app返回两次vsync信号。
SingleSuppressCallback:返回一次vsync之后就是这个状态。
接下来我们看一下 threadMain 函数里面:
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {DisplayEventConsumers consumers;while (mState != State::Quit) {std::optional<DisplayEventReceiver::Event> event;。。。。。。bool vsyncRequested = false;// Find connections that should consume this event.auto it = mDisplayEventConnections.begin();//对所有的connection进行遍历while (it != mDisplayEventConnections.end()) {if (const auto connection = it->promote()) {//因为前面 request 的时候赋值为 Single, 所以为 truevsyncRequested |= connection->vsyncRequest != VSyncRequest::None;。。。。。。}。。。。。。}。。。。。。State nextState;if (mVSyncState && vsyncRequested) {//将 nextState 设置为 State::VSyncnextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;}。。。。。。if (mState != nextState) {if (mState == State::VSync) {mVSyncSource->setVSyncEnabled(false);} else if (nextState == State::VSync) {// 1、这里开始计算等待时间、并进行定时mVSyncSource->setVSyncEnabled(true);}mState = nextState;}。。。。。。}
}
因为前面将 nextState 设置为 State::VSync,而且 mState 初始化不为 State::VSync,所以会执行到 1 的位置开始进行vsync等待时间,并进行定时。
2、计算 app vsync 的等待时长和定时
void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {// 这个参数决定了是否停止定时mStarted = true;mWorkDuration = workDuration;mReadyDuration = readyDuration;//计算并定时auto const scheduleResult =mRegistration.schedule({.workDuration = mWorkDuration.count(),.readyDuration = mReadyDuration.count(),.earliestVsync = mLastCallTime.count()});}
这里将mStarted赋值为true表示开始循环定时,当停止定时就会将mStarted设置为false。
mRegistration.schedule最终会调用到VSyncDispatchTimerQueue::schedule(),在sf vsync文章里面我们说到了VSyncDispatchTimerQueue主要是负责vsync的定时和回调事件。
ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,ScheduleTiming scheduleTiming) {ScheduleResult result;{std::lock_guard lock(mMutex);auto it = mCallbacks.find(token);if (it == mCallbacks.end()) {return result;}auto& callback = it->second;auto const now = mTimeKeeper->now();/* If the timer thread will run soon, we'll apply this work update via the callback* timer recalculation to avoid cancelling a callback that is about to fire. */auto const rearmImminent = now > mIntendedWakeupTime;if (CC_UNLIKELY(rearmImminent)) {callback->addPendingWorkloadUpdate(scheduleTiming);return getExpectedCallbackTime(mTracker, now, scheduleTiming);}//1、计算出定时时长result = callback->schedule(scheduleTiming, mTracker, now);if (!result.has_value()) {return result;}
// mIntendedWakeupTime 默认是无穷大, 所以这里肯定会通过if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {//2、真正开始定时rearmTimerSkippingUpdateFor(now, it);}}return result;
}
(1)计算定时时长
VSyncDispatchTimerQueue.cpp
ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,VSyncTracker& tracker, nsecs_t now) {//通过 VsyncTracker 计算出下一次软件Vsync的时间,在sf vsync 文章中我们讲到VsyncTracker是负责通过 hwVsync 计算出软件vsync的模型 auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));// 计算出下次唤醒的时间auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;//将计算出的唤醒时间放到 mArmedInfo mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};return getExpectedCallbackTime(nextVsyncTime, timing);
}
这里的 VSyncDispatchTimerQueueEntry 就是 VSyncDispatchTimerQueue 里面的 mCallbacks (这是一个map)的 value 的类型,map的可以是Token。VSyncDispatchTimerQueueEntry 和app进程的Connection是一一对应的,里面记录了WakeupTime 和 VSyncDispatch::Callback(在定时到的时候会用到)。
关于软件vsync模型的计算我们后面在介绍。
(2)进行定时
void Timer::alarmAt(std::function<void()> callback, nsecs_t time) {std::lock_guard lock(mMutex);。。。。。。if (timerfd_settime(mTimerFd, TFD_TIMER_ABSTIME, &new_timer, &old_timer)) {ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);}
}
这里就是通过mTimerFd来进行定时的,当时间到了,监听了mTimerFd的就会被唤醒。我们来看一下具体在哪监听的:
bool Timer::dispatch() {。。。。。。if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mTimerFd, &timerEvent) == -1) {ALOGE("Error adding timer fd to epoll dispatch loop");return true;}。。。。。。while (true) {。。。。。。int nfds = epoll_wait(mEpollFd, events, DispatchType::MAX_DISPATCH_TYPE, -1);。。。。。for (auto i = 0; i < nfds; i++) {if (events[i].data.u32 == DispatchType::TIMER) {。。。。。{cb = mCallback;}if (cb) {setDebugState(DebugState::InCallback);//执行cb();setDebugState(DebugState::Running);}}。。。。。。}}
}
从代码我们可以看出是通过epoll来监听mTimerFd的变化,当定时时间到就会往下执行,然后执行cb(),也就是mCallback进行回调。
二、事件的回调
接下来我们看一下事件的回调流程具体是怎么样的。
mCallback是在Timer::alarmAt()函数被调用的时候传递过来的,那么它具体是什么呢?
所以执行mCallBack就是执行VSyncDispatchTimerQueue::timerCallback 函数:
void VSyncDispatchTimerQueue::timerCallback() {struct Invocation {std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;nsecs_t vsyncTimestamp;nsecs_t wakeupTimestamp;nsecs_t deadlineTimestamp;};。。。。。。for (auto const& invocation : invocations) {//这里执行的是 VSyncDispatchTimerQueueEntry 的 callback 函数invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,invocation.deadlineTimestamp);}
}
我们追寻溯源看一下 VSyncDispatchTimerQueueEntry 的 callback 具体是在哪被赋值的。
VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(Callback callback, std::string callbackName) {std::lock_guard lock(mMutex);return CallbackToken{mCallbacks.emplace(++mCallbackToken,std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),std::move(callback),mMinVsyncDistance)).first->first};
}
那么registerCallback又是在哪调用的呢。
VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,VSyncDispatch::Callback callback,std::string callbackName): mDispatch(dispatch),mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))),mValidToken(true) {}
是在VSyncCallbackRegistration构造函数里面调用了registerCallback。我们接着往下寻找:
从这我们知道了 VSyncDispatchTimerQueueEntry 的 callback是CallbackRepeater::callback函数,我们看一下这个函数:
void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {。。。。。。// 1mCallback(vsyncTime, wakeupTime, readyTime);{std::lock_guard lock(mMutex);// 2if (!mStarted) {return;}// 3auto const scheduleResult =mRegistration.schedule({.workDuration = mWorkDuration.count(),.readyDuration = mReadyDuration.count(),.earliestVsync = vsyncTime});LOG_ALWAYS_FATAL_IF(!scheduleResult.has_value(), "Error rescheduling callback");}}
我们可以看到又执行了mCallback(vsyncTime, wakeupTime, readyTime),而且 2 处有一个判断使用了 mStarted, 如果mStarted为false则不会继续下一次的定时,这样就停止了 vsync 的申请。反之则会在注释 3处继续调用mRegistration.schedule进行下一次的定时。
从前面我们可以知道 mCallback 是在 CallbackRepeater 创建的时候传过来的,我们找一下:
mCallbackRepeater =std::make_unique<CallbackRepeater>(vSyncDispatch,std::bind(&DispSyncSource::onVsyncCallback, this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3),name, workDuration, readyDuration,std::chrono::steady_clock::now().time_since_epoch());
所有CallbackRepeater 的 mCallback 是 DispSyncSource::onVsyncCallback:
void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,nsecs_t readyTime) {VSyncSource::Callback* callback;{std::lock_guard lock(mCallbackMutex);callback = mCallback;}。。。。。。if (callback != nullptr) {callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});}
}
会执行到callback->onVSyncEvent函数, 因为 EventThread 继承了 VSyncSource::Callback, 所以我们知道最后执行的是EventThread::onVSyncEvent
void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {。。。。。。mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,vsyncData.expectedPresentationTime,vsyncData.deadlineTimestamp));mCondition.notify_all();
}
EventThread::onVSyncEvent就是往mPendingEvents添加一个Event,然后进行线程唤醒,那么我们接下来回到 EventThread 的 threadMain 函数:
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {DisplayEventConsumers consumers;while (mState != State::Quit) {std::optional<DisplayEventReceiver::Event> event;// Determine next event to dispatch.// onVSyncEvent 函数里添加了 Event,所以mPendingEvents有元素if (!mPendingEvents.empty()) {// 获取到event,并将这个event从mPendingEvents里面移除event = mPendingEvents.front();mPendingEvents.pop_front();。。。。。。}bool vsyncRequested = false;// Find connections that should consume this event.auto it = mDisplayEventConnections.begin();while (it != mDisplayEventConnections.end()) {if (const auto connection = it->promote()) {//connection->vsyncRequest 还是 SinglevsyncRequested |= connection->vsyncRequest != VSyncRequest::None;// shouldConsumeEvent 判断 connection->vsyncRequest 的值,并将其置为下一阶段if (event && shouldConsumeEvent(*event, connection)) {// 将请求了 vsync 的connection 放到 consumersconsumers.push_back(connection);}++it;} else {it = mDisplayEventConnections.erase(it);}}// 前面已经往consumers添加了需要vsync信号的connection,所以不为空if (!consumers.empty()) {// 2、开始事件派发dispatchEvent(*event, consumers);consumers.clear();}State nextState;if (mVSyncState && vsyncRequested) {nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;} else {......}// mState 和 nextState 都是 State::VSyncif (mState != nextState) {......}// 因为 event 不为空所以继续下一次循环if (event) {continue;}if (mState == State::Idle) {mCondition.wait(lock);} else {。。。。。。// 1 if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {。。。。。。}}}
}
前面我们说了 nextState 被赋值了 State::VSync, 所以在完成定时之后会接着往下执行 1 处的等待,而 EventThread::onVSyncEvent 里面唤醒的等待就是这个,那么就会接着执行下一个循环。注释 2 处开始往app端派发vsync事件,使用的是本地socket方式进行跨进程通信。
三、app 再次请求 vsync
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {。。。。。。if (connection->vsyncRequest == VSyncRequest::None) {connection->vsyncRequest = VSyncRequest::Single;mCondition.notify_all();} else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {connection->vsyncRequest = VSyncRequest::Single;}
}
当app端再次请求vysnc信号时,如果 connection->vsyncRequest == VSyncRequest::SingleSuppressCallback,则只会将connection->vsyncRequest 设置为Single,不用唤醒线程。
四、vsync请求停止
要探寻vsync请求的停止,我们要从 EventThread::threadMain 开始。
// 当定时到了,进行事件派发的时候,如果connection->vsyncRequest == SingleSuppressCallback,
//shouldConsumeEvent函数里面会将 shouldConsumeEvent 设置为 None。
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {DisplayEventConsumers consumers;while (mState != State::Quit) {。。。。。。bool vsyncRequested = false;// Find connections that should consume this event.auto it = mDisplayEventConnections.begin();while (it != mDisplayEventConnections.end()) {if (const auto connection = it->promote()) {// 3vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;// 1if (event && shouldConsumeEvent(*event, connection)) {consumers.push_back(connection);}++it;} else {it = mDisplayEventConnections.erase(it);}}if (!consumers.empty()) {dispatchEvent(*event, consumers);consumers.clear();}State nextState;// 4if (mVSyncState && vsyncRequested) {nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;} else {nextState = State::Idle;}// 5if (mState != nextState) {if (mState == State::VSync) {mVSyncSource->setVSyncEnabled(false);} else if (nextState == State::VSync) {mVSyncSource->setVSyncEnabled(true);}mState = nextState;}// 2if (event) {continue;}// Wait for event or client registration/request.// 6if (mState == State::Idle) {mCondition.wait(lock);} else {......}}
}
注释 1 : 当定时到了,进行事件派发的时候,如果connection->vsyncRequest == SingleSuppressCallback,shouldConsumeEvent函数里面会将 shouldConsumeEvent 设置为 None。
注释 2 : 会进行下一个循环。
注释3 :是下一个循环的逻辑,因为connection->vsyncRequest == None,所以vsyncRequested 为赋值为false。
注释 4:vsyncRequested 为 false,所以 nextState = State::Idle。
注释 5:nextState 已经在前面被置为 Idle,但是mState还没有改变依然是State::VSync,所以会执行 mVSyncSource->setVSyncEnabled(false)。
注释 6:mState 在前面被赋值为 idle,线程进行等待。
void stop() {std::lock_guard lock(mMutex);LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");mStarted = false;//取消上一次的定时mRegistration.cancel();}
mVSyncSource->setVSyncEnabled(false)最终会调用到CallbackRepeater->stop(),将重要的参数mStarted 置为false,并且取消掉上一次的定时。
而在CallbackRepeater的callback回调函数里面,通过mStarted来判断是否进行下一次的定时,这时候mStarted为false,所以停止了定时。
DispSyncSource.cpp文件里面。
void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {。。。。。。{std::lock_guard lock(mMutex);if (!mStarted) {return;}。。。。。。}}