Android 13 VSYNC重学习
引言
学无止境,一个字干就完事!
源码参考基于Android 13 aosp!
一. Android VSync模块开胃菜
在开始正式的分析之前,我们先简单对Android的Vsync模块简单介绍下,如下图所示,其中:
- HW_VSync是由屏幕产生的脉冲信号,用于控制屏幕的刷新
- VSync-app和VSync-sf统称为软件VSync,它们是由SurfaceFlinger通过模拟硬件VSync而产生的VSync信号量,再分发给app和sf用来控制它们的合成节奏
二. Android VSync小结
这里有几点需要补充:
-
VSync-sf是没有对应的EventThread和DispSyncSource
-
VSync-app和VSync-appSf各自都有对应的EventThread和DispSyncSource
-
VSync-sf和VSync-app以及Sync-appSf通过Scheduler的成员mVsyncSchedule指向的VSyncDispatchTimerQueue实例对象关联
Android下VSync设计,牵涉的核心关系图如下:
2.1 VSync信号的分类
VSync信号分为两种:硬件VSync信号HW-VSync和软件VSync信号SW-VSync。SW-VSync信号由SW-VSync模型产生。HW-VSync信号负责对SW-VSync模型进行校准。
2.2 HW-Vsync信号的开启
三种场景下会开启硬件VSync信号HW-VSync会对软件VSync信号SW-VSync进行校准
-
SurfaceFlinger初始化。
-
连续两次请求VSync-app信号的时间间隔超过750ms。
-
SurfaceFlinger合成后,添加FenceTime到VSyncTracker中导致模型计算误差过大。
2.3 SW-VSync模型与计算
谷歌官方采用一元线性回归分析预测法(最小二乘法),通过采样的HW-VSync信号样本(屏幕刷新率),计算对应的SW-VSync信号周期。最终得到一条y=bx+a的拟合曲线。其中,b称为回归系数,a称为截距。SW-VSync模型就是这这条曲线的回归系数和截距。
2.4 SW-VSync信号的分类
SW-VSync信号也分为两种,VSync-sf信号和Vsync-app信号。这两个信号,各司其职:
- VSync-sf信号用于控制SurfaceFlinger的Layer合成
- VSync-app信号用于控制App渲染UI
VSync-sf信号和VSync-app信号是在SW-VSync信号的基础上通过叠加不同的偏移量产生,这些偏移量被称为VSync相位偏移。由于偏移量不同VSync-sf信号和VSync-app信号的回调时机也不同。
三. VSync-sf的申请和分发
VSync-sf用于控制SurfaceFlinger合成和渲染一帧图像。当SurfaceFlinger上帧时(BufferQueue中有新的GraphicBuffer),SurfaceFlinger会触发MessageQueue的scheduleFrame方法。接下来我们看下,VSync-sf是如何完成从申请到分发的流程。
3.1 VSync-sf的申请
c
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);
}
}
}
3.2 VSync-sf的分发
那么VSync-df的callback是怎么注册到VSyncDispatchTimerQueue的呢,这个我们看下:
c
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中,我们看下它的实现:
c
//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的申请和分发
在开始后续的章节编写前,我们先重点申明下:
VSync-app用于控制App的UI渲染
VSync-app用于控制App的UI渲染
VSync-app用于控制App的UI渲染
4.1 VSync-app的申请
当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信号的分发。
c
//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方法。
c
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信号的发送。
4.2 VSync-app的分发
当定时时间到达时,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流程:
c
//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方法。
c
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是如何处理分发事件的:
c
//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事件分发过程源码分析