赞
踩
学无止境,一个字干就完事!
源码参考基于Android 13 aosp!
在开始正式的分析之前,我们先简单对Android的Vsync模块简单介绍下,如下图所示,其中:
这里有几点需要补充:
VSync-sf是没有对应的EventThread和DispSyncSource
VSync-app和VSync-appSf各自都有对应的EventThread和DispSyncSource
VSync-sf和VSync-app以及Sync-appSf通过Scheduler的成员mVsyncSchedule指向的VSyncDispatchTimerQueue实例对象关联
Android下VSync设计,牵涉的核心关系图如下:
VSync信号分为两种:硬件VSync信号HW-VSync和软件VSync信号SW-VSync。SW-VSync信号由SW-VSync模型产生。HW-VSync信号负责对SW-VSync模型进行校准。
三种场景下会开启硬件VSync信号HW-VSync会对软件VSync信号SW-VSync进行校准
SurfaceFlinger初始化。
连续两次请求VSync-app信号的时间间隔超过750ms。
SurfaceFlinger合成后,添加FenceTime到VSyncTracker中导致模型计算误差过大。
谷歌官方采用一元线性回归分析预测法(最小二乘法),通过采样的HW-VSync信号样本(屏幕刷新率),计算对应的SW-VSync信号周期。最终得到一条y=bx+a的拟合曲线。其中,b称为回归系数,a称为截距。SW-VSync模型就是这这条曲线的回归系数和截距。
SW-VSync信号也分为两种,VSync-sf信号和Vsync-app信号。这两个信号,各司其职:
VSync-sf信号和VSync-app信号是在SW-VSync信号的基础上通过叠加不同的偏移量产生,这些偏移量被称为VSync相位偏移。由于偏移量不同VSync-sf信号和VSync-app信号的回调时机也不同。
VSync-sf用于控制SurfaceFlinger合成和渲染一帧图像。当SurfaceFlinger上帧时(BufferQueue中有新的GraphicBuffer),SurfaceFlinger会触发MessageQueue的scheduleFrame方法。接下来我们看下,VSync-sf是如何完成从申请到分发的流程。
SurfaceFlinger::scheduleCommit(...)//请求上帧 mScheduler->scheduleFrame()//MessageQueue.cpp mVsync.registration->schedule()//这里的registration实现是VSyncCallbackRegistration,定义在Scheduler/VSyncDispatchTimerQueue.cpp mDispatch.get().schedule()//这里的mDispatch指向VSyncDispatchTimerQueue对象 /** * @brief * * @param token * @param scheduleTiming * @return ScheduleResult * 1)根据CallbackToken找到所有满足要求的VSyncDispatchTimerQueueEntry。VSyncDispatchTimerQueueEntry是VSyncDispatchTimerQueue中对外部VSync信号请求的封装。 * 2)遍历调用VSyncDispatchTimerQueue的schedule方法,计算下一次VSync信号的发送时间。 * 3)对发射时间进行定时,等待下一次VSync信号的发送 */ ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, ScheduleTiming scheduleTiming) { ... //根据CallbackToken找到所有满足要求的VSyncDispatchTimerQueueEntry。VSyncDispatchTimerQueueEntry是VSyncDispatchTimerQueue中对外部VSync信号请求的封装。 auto it = mCallbacks.find(token); auto& callback = it->second; //遍历调用VSyncDispatchTimerQueue的schedule方法,计算下一次VSync信号的发送时间 result = callback->schedule(scheduleTiming, mTracker, now); //对发射时间进行定时,等待下一次VSync-sf信号的发送 rearmTimerSkippingUpdateFor(now, it); VSyncDispatchTimerQueue::setTimer() void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) { mIntendedWakeupTime = targetTime; mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this), mIntendedWakeupTime); mLastTimerSchedule = mTimeKeeper->now(); } /** * @brief * 1)遍历CallbackMap找到达到唤醒时间的VSyncDispatchTimerQueueEntry,并封装成Invocation,加入Invocation列表。 * 2)遍历Invocation列表,通过Invocation获取VSyncDispatchTimerQueueEntry,并调用VSyncDispatchTimerQueueEntry的callback方法分发VSync信号。 */ //Scheduler/VSyncDispatchTimerQueue.cpp void VSyncDispatchTimerQueue::timerCallback() { struct Invocation { std::shared_ptr<VSyncDispatchTimerQueueEntry> callback; nsecs_t vsyncTimestamp; nsecs_t wakeupTimestamp; nsecs_t deadlineTimestamp; }; std::vector<Invocation> invocations; { std::lock_guard lock(mMutex); auto const now = mTimeKeeper->now(); mLastTimerCallback = now; for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) { auto& callback = it->second; auto const wakeupTime = callback->wakeupTime(); if (!wakeupTime) { continue; } auto const readyTime = callback->readyTime(); auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0)); if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) { callback->executing(); invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime, *readyTime}); } } mIntendedWakeupTime = kInvalidTime; rearmTimer(mTimeKeeper->now()); } for (auto const& invocation : invocations) { invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp, invocation.deadlineTimestamp); } } }
那么VSync-df的callback是怎么注册到VSyncDispatchTimerQueue的呢,这个我们看下:
SurfaceFlinger::initScheduler(...) mScheduler->initVsync(...)//实现在Scheduler/MessageQueue.cpp中 mVsync.registration = std::make_unique< scheduler::VSyncCallbackRegistration>(dispatch, std::bind(&MessageQueue::vsyncCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), "sf");//这里的dispatch指向VSyncDispatchTimerQueue //Scheduler/VSyncDispatchTimerQueue.cpp VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch, VSyncDispatch::Callback callback, std::string callbackName) : mDispatch(dispatch), mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))), mValidToken(true) {} VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback( Callback callback, std::string callbackName) { std::lock_guard lock(mMutex); return CallbackToken{//最终注册到了mCallbacks中 mCallbacks .emplace(++mCallbackToken, std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName), std::move(callback), mMinVsyncDistance)) .first->first}; }
所以最后VSync-sf的分发会调用到MessageQueue::vsyncCallback中,我们看下它的实现:
//Scheduler/MessageQueue.cpp MessageQueue::vsyncCallback(...) mHandler->dispatchFrame(vsyncId, vsyncTime) mQueue.mLooper->sendMessage(this, Message()) //Handle的handleMessage接收前面发过来的消息 void MessageQueue::Handler::handleMessage(const Message&) { mFramePending.store(false); const nsecs_t frameTime = systemTime(); auto& compositor = mQueue.mCompositor;//这里的compositor实现类是SurfaceFlinger if (!compositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) { return; } compositor.composite(frameTime, mVsyncId); compositor.sample(); }
在开始后续的章节编写前,我们先重点申明下:
VSync-app用于控制App的UI渲染
VSync-app用于控制App的UI渲染
VSync-app用于控制App的UI渲染
当Choreographer通过FrameDisplayEventReceiver调用scheduleVsync方法时,会触发VSync-app信号的申请。在FrameDisplayEventReceiver的scheduleVsync方法中,会调用nativeScheduleVsync方法。
FrameDisplayEventReceiver的nativeScheduleVsync方法对应的native实现为android_view_DisplayEventReceiver的nativeScheduleVsync函数。
在nativeScheduleVsync函数中,主要做了两件事:
获取native层的DisplayEventDispatcher。
调用DisplayEventDispatcher的scheduleVsync方法,请求VSync信号。
在DisplayEventDispatcher的scheduleVsync方法中,会调用DisplayEventReceiver的requestNextVsync方法。
在DisplayEventReceiver的requestNextVsync方法中,会调用IDisplayEventConnection的requestNextVsync方法。
IDisplayEventConnection是一个Binder类,对应bn端的实现类为BnDisplayEventConnection。而EventThreadConnection继承自BnDisplayEventConnection,因此实际调用的是EventThreadConnection的requestNextVsync方法。
在EventThreadConnection的requestNextVsync方法中,会调用EventThread的requestNextVsync方法。
在EventThread的requestNextVsync方法中,主要做了三件事:
开启硬件VSync信号对软件VSync信号进行校准。
标记EventThreadConnection的vsyncRequest,为后续信号分发做准备。
唤起EventThread对应的线程继续执行VSync信号的分发。
//Scheduler/EventThread.cpp void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) { if (connection->resyncCallback) { /** * @brief * 调用到Scheduler::resync * 开启硬件Vsync信号对软件Vsync信号进行校准 */ connection->resyncCallback(); } std::lock_guard<std::mutex> lock(mMutex); if (connection->vsyncRequest == VSyncRequest::None) { connection->vsyncRequest = VSyncRequest::Single; mCondition.notify_all();//唤起EventThread中的线程 } else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) { connection->vsyncRequest = VSyncRequest::Single; } }
在EventThread的threadMain中,会通过VSyncCallbackRegistration请求或取消VSync信号。
如果是请求VSync信号,会调用VSyncCallbackRegistration的schedule方法。在VSyncCallbackRegistration的schedule方法,会调用VSyncDispatch的schedule方法。
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
if (mState != nextState) {
if (mState == State::VSync) {
mVSyncSource->setVSyncEnabled(false);
} else if (nextState == State::VSync) {
mVSyncSource->setVSyncEnabled(true);
}
mState = nextState;
}
}
之后的流程与VSync-sf信号的申请流程相同。在VSyncDispatchTimerQueue的schedule方法中,会调用scheduleLocked方法。
在VSyncDispatchTimerQueue的scheduleLocked方法中,主要做了三件事:
根据CallbackToken找到所有满足要求的VSyncDispatchTimerQueueEntry。VSyncDispatchTimerQueueEntry是VSyncDispatchTimerQueue中对外部VSync信号请求的封装。
遍历调用VSyncDispatchTimerQueue的schedule方法,计算下一次VSync信号的发送时间。
对发射时间进行定时,等待下一次VSync信号的发送。
当定时时间到达时,TimerKeeper会回调VSyncDispatchTimerQueue的timerCallback方法。
在VSyncDispatchTimerQueue的timerCallback方法方法中,主要做了两件事:
遍历CallbackMap找到达到唤醒时间的VSyncDispatchTimerQueueEntry,并封装成Invocation,加入Invocation列表。
遍历Invocation列表,通过Invocation获取VSyncDispatchTimerQueueEntry,并调用VSyncDispatchTimerQueueEntry的callback方法分发VSync信号。
在VSyncDispatchTimerQueueEntry的callback方法中,会调用类型为CallbackRepeater::callbackk,然后在该方法中接着调用mCallback(vsyncTime, wakeupTime, readyTime)方法,而这里的mCallback(指向DispSyncSource::onVsyncCallback,最后回调EventThread的onVSyncEvent方法。
对于上述的分发流程是不是还有点懵逼,我们反过来看看VSync-app分发的注册,其核心是DispSyncSource和EventThread以及VSyncDispatchTimerQueue的各种回调callback流程:
//Scheduler/VSyncDispatchTimerQueue.cpp 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}; } //Scheduler/VSyncDispatchTimerQueue.cpp VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch, VSyncDispatch::Callback callback, std::string callbackName) : mDispatch(dispatch), mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))), mValidToken(true) {} //Scheduler/DispSyncSource.cpp class CallbackRepeater { public: CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, std::chrono::nanoseconds notBefore) : mName(name), mCallback(cb), //VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex); mRegistration(dispatch, std::bind(&CallbackRepeater::callback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), mName), mStarted(false), mWorkDuration(workDuration), mReadyDuration(readyDuration), mLastCallTime(notBefore) {} ~CallbackRepeater() { std::lock_guard lock(mMutex); mRegistration.cancel(); } void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) { std::lock_guard lock(mMutex); mStarted = true; mWorkDuration = workDuration; mReadyDuration = readyDuration; auto const scheduleResult = mRegistration.schedule({.workDuration = mWorkDuration.count(), .readyDuration = mReadyDuration.count(), .earliestVsync = mLastCallTime.count()}); LOG_ALWAYS_FATAL_IF((!scheduleResult.has_value()), "Error scheduling callback"); } void stop() { std::lock_guard lock(mMutex); LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped"); mStarted = false; mRegistration.cancel(); } void dump(std::string& result) const { std::lock_guard lock(mMutex); const auto relativeLastCallTime = mLastCallTime - std::chrono::steady_clock::now().time_since_epoch(); StringAppendF(&result, "\t%s: ", mName.c_str()); StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ", mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f); StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f, mStarted ? "running" : "stopped"); } private: void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) { { std::lock_guard lock(mMutex); mLastCallTime = std::chrono::nanoseconds(vsyncTime); } mCallback(vsyncTime, wakeupTime, readyTime); { std::lock_guard lock(mMutex); if (!mStarted) { return; } auto const scheduleResult = mRegistration.schedule({.workDuration = mWorkDuration.count(), .readyDuration = mReadyDuration.count(), .earliestVsync = vsyncTime}); LOG_ALWAYS_FATAL_IF(!scheduleResult.has_value(), "Error rescheduling callback"); } } const std::string mName; scheduler::VSyncDispatch::Callback mCallback; mutable std::mutex mMutex; VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex); bool mStarted GUARDED_BY(mMutex) = false; std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns; std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns; std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns; }; mAppConnectionHandle = mScheduler->createConnection("app" .....) Scheduler::createConnection() auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration) return std::make_unique<scheduler::DispSyncSource>(mVsyncSchedule->getDispatch(), mVsyncSchedule->getTracker(), workDuration, readyDuration, traceVsync, name); //std::unique_ptr<CallbackRepeater> mCallbackRepeater; 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()); mVSyncSource->setCallback(this);//为DispVsyncSource设置回调 void DispSyncSource::setCallback(VSyncSource::Callback* callback) { std::lock_guard lock(mCallbackMutex); mCallback = callback; } //最终整理出来的Vsync-app分发流程为,各种弯弯绕绕: VSyncDispatchTimerQueue::timerCallback()//Scheduler/VSyncDispatchTimerQueue.cpp invocation.callback->callback(...)//这里的callback指向VSyncDispatchTimerQueueEntry::callback,Scheduler/VSyncDispatchTimerQueue.cpp mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp)//这里的 mCallback指向CallbackRepeater::callback,实现在Scheduler/DispSyncSource.cpp mCallback(vsyncTime, wakeupTime, readyTime)//这里的callback指向DispSyncSource::onVsyncCallback。是现在Scheduler/DispSyncSource.cpp callback = mCallback; callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime})//这里的callback指向EventThread::onVSyncEvent
在EventThread的onVSyncEvent方法中,主要做了三件事:
调用makeVSync函数,创建Event。
将Event加入到vector<DisplayEventReceiver::Event> 中。
唤醒等待线程,执行threadMain方法。
void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {
std::lock_guard<std::mutex> lock(mMutex);
LOG_FATAL_IF(!mVSyncState);
//包装为DisplayEventReceiver::Event对象,存入mPendingEvents尾部
mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
vsyncData.expectedPresentationTime,
vsyncData.deadlineTimestamp));
//唤醒线程
mCondition.notify_all();
}
我们接下来看EventThread是如何处理分发事件的:
//Scheduler/EventThread.cpp 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. if (!mPendingEvents.empty()) { event = mPendingEvents.front(); mPendingEvents.pop_front(); ... } // Find connections that should consume this event. auto it = mDisplayEventConnections.begin(); while (it != mDisplayEventConnections.end()) { if (const auto connection = it->promote()) { vsyncRequested |= connection->vsyncRequest != VSyncRequest::None; //用来在任务的循环执行中保存当前Vsync信号的消费者 if (event && shouldConsumeEvent(*event, connection)) { consumers.push_back(connection);//这里的consumers就是待分发的目标 } ++it; } else { it = mDisplayEventConnections.erase(it); } } /** * @brief * 在该方法中,会循环分发信号,主要做了五件事情 * 1) 从Vsync信息队列中获取消息 * 2)收集监听Vsync信号的EventThreadConnection,并加入到consumers中 * 3) 调用dispatchEvent方法来分发Vsync信号 * 4)计算当前状态,根据状态请求或取消下一次VSync信号 * 5)如果没有Vsync信号需要分发,线程进入等待状态 */ if (!consumers.empty()) { dispatchEvent(*event, consumers); consumer->postEvent(copy) DisplayEventReceiver::sendEvents(...) consumers.clear(); }
最终VSync-app分发的事件会被Choreographer模块接收,开始安排应用相关的渲染UI逻辑!
Andoid SurfaceFlinger(二) VSYNC的开始,连续,结束
VSYNC研究-最后的窗户纸
Android 12(S) 图像显示系统 - SurfaceFlinger之VSync-上篇(十六)
Android 12(S) 图像显示系统 - SurfaceFlinger 之 VSync - 中篇(十七)
深度详解 Android S(12.0)屏幕刷新机制之 Choreographer
View绘制流程3-Vsync信号是如何发送和接受的
Android R Vsync相关梳理
显示框架之深入Vsync原理
App/Sf的Vsync部分源码流程结合perfetto/systrace分析
Android-View绘制原理(02)-VSync原理之SurfaceFlinger篇
一文搞定Android VSync来龙机制去脉
VSync信号系统与SurfaceFlinger
SurfaceFlinger-Vsync信号
Android VSync事件分发过程源码分析
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。