SurfaceFlinger VSync信号
简介
Vsync是垂直同步信号,这个是用于约束渲染速度的信号,主要是为了防止出现“撕裂”的情况,所谓“撕裂”,就是画面分离的,一个图像被分成两个图像。
出现这个问题的原因是渲染和显示的速度不同导致的。举个例子。显示器刷新率是60HZ,而GPU渲染速度一秒钟更新90次,这样相当于显示器显示一帧的时间gpu可以渲染1.5屏图片,那么就会出现屏幕显示的时候,显示出第一帧的1/2图像和第二帧的1/2的图像,这样如果两帧图像内容有变化,就会出现撕裂。
而Vsync就是为了解决这个问题,比如一般android的Vsync信号是60HZ或者120HZ,gpu如果想要渲染,就必须等到一次vsync信号,只要gpu渲染和显示屏处理速度都大于等于vsync帧率,就可以避免撕裂且不会卡顿。
而Android的显示流程中,一般会用到两次VSync信号。app会向SurfaceFlinger请求VSync信号来渲染内容,SurfaceFlinger也会用VSync信号来合成内容。由于合成依赖于渲染,所以合成的内容是上一帧VSync信号渲染的内容。
Android的VSync信号是由SurfaceFlinger用软件模拟的,但是会根据hwc硬件的VSync定期更新修正。
我们会分别介绍app请求VSync信号,SurfaceFlinger侧初始化Schduler以及产生VSync信号。
app请求VSync信号
当View需要重新绘制时,都会调用invalidate(),会递归调用ViewParent的invalidate(),最终会调用到ViewRootImpl的invalidate()来请求下一个VSync,我们就从这里开始看。
1.1 ViewRootImpl.invalidate
void invalidate() {
mDirty.set(0, 0, mWidth, mHeight);
if (!mWillDrawSoon) {
// 详见1.2
scheduleTraversals();
}
}
1.2 ViewRootImpl.scheduleTraversals
调用Choreographer.postCallback请求下一个VSync
void scheduleTraversals() {
// 防止重复请求
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 配置异步消息,VSync消息优先处理
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过Choreographer请求下一个VSync,详见1.3
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
1.3 Choreographer.postCallback
postCallback->postCallbackDelayed->postCallbackDelayedInternal
前两个方法只是传入默认参数和参数非法校验,我们直接看postCallbackDelayedInternal
主要就是调用scheduleFrameLocked,但是在这之前我们还记录来一个type为CALLBACK_TRAVERSAL的CallbackQueue,里面的action是mTraversalRunnable,这个是后面VSync回来后回调的方法。
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
// 入参delayMillis是0,立刻执行
final long dueTime = now + delayMillis;
// 记录action,后续回调会使用,这里的type是Choreographer.CALLBACK_TRAVERSAL
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
// 走的这里,详见1.4
scheduleFrameLocked(now);
} else {
// 如果有延时,post一个消息,最终还是调用scheduleFrameLocked
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
1.4 scheduleFrameLocked
主要工作是调用scheduleVsyncLocked
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
// 默认都是走这里,使用VSync信号
if (USE_VSYNC) {
// 如果当前是主线程,直接调用scheduleVsyncLocked,详见1.5
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
// 这里post消息,其实还是调用了scheduleVsyncLocked
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
// 。。。
}
}
}
1.5 scheduleVsyncLocked
调用了FrameDisplayEventReceiver的scheduleVsync
FrameDisplayEventReceiver继承DisplayEventReceiver,实际调用的DisplayEventReceiver的scheduleVsync
private void scheduleVsyncLocked() {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
// 详见1.6
mDisplayEventReceiver.scheduleVsync();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
1.6 DisplayEventReceiver.scheduleVsync
jni调用nativeScheduleVsync
public void scheduleVsync() {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
+ "receiver has already been disposed.");
} else {
//详见1.7
nativeScheduleVsync(mReceiverPtr);
}
}
1.7 nativeScheduleVsync
调用了NativeDisplayEventReceiver::scheduleVsync
NativeDisplayEventReceiver继承DisplayEventDispatcher,实际调用DisplayEventDispatcher::scheduleVsync
static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
sp<NativeDisplayEventReceiver> receiver =
reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
// 详见1.8
status_t status = receiver->scheduleVsync();
//。。。如果返回值不为0,抛出java异常
}
1.8 DisplayEventDispatcher::scheduleVsync
处理之前的事件,然后调用DisplayEventReceiver::requestNextVsync请求下一个VSync信号。
status_t DisplayEventDispatcher::scheduleVsync() {
// 防止重复同时请求
if (!mWaitingForVsync) {
ALOGV("dispatcher %p ~ Scheduling vsync.", this);
// Drain all pending events.
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
VsyncEventData vsyncEventData;
// 处理pending事件
if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
}
// 请求下一个VSync信号,详见1.9
status_t status = mReceiver.requestNextVsync();
if (status) {
ALOGW("Failed to request next vsync, status=%d", status);
return status;
}
mWaitingForVsync = true;
mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC);
}
return OK;
}
1.9 DisplayEventReceiver::requestNextVsync()
这里mEventConnection是一个EventThreadConnection,是binder对象,requestNextVsync会调用到SurfaceFlinger侧。我们到这先看看EventThreadConnection是怎么创建的。
status_t DisplayEventReceiver::requestNextVsync() {
if (mEventConnection != nullptr) {
// 这里是个Binder,调用到SurfaceFlinger侧。详见2.1
mEventConnection->requestNextVsync();
return NO_ERROR;
}
return mInitError.has_value() ? mInitError.value() : NO_INIT;
}
1.9.1 nativeInit
前面Choreographer里面持有一个java层DisplayEventReceiver,DislayEventReceiver构造会调用nativeInit,我们就从这里开始介绍。
构造了一个NativeDisplayEventReceiver,而NativeDisplayEventReceiver继承DisplayEventDispatcher
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject vsyncEventDataWeak,
jobject messageQueueObj, jint vsyncSource, jint eventRegistration,
jlong layerHandle) {
//。。。
// 构造了一个NativeDisplayEventReceiver,详见1.9.2
sp<NativeDisplayEventReceiver> receiver =
new NativeDisplayEventReceiver(env, receiverWeak, vsyncEventDataWeak, messageQueue,
vsyncSource, eventRegistration, layerHandle);
status_t status = receiver->initialize();
//。。。
return reinterpret_cast<jlong>(receiver.get());
}
1.9.2 DisplayEventDispatcher构造
主要是构造了一个DisplayEventReceiver
DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
gui::ISurfaceComposer::VsyncSource vsyncSource,
EventRegistrationFlags eventRegistration,
const sp<IBinder>& layerHandle)
: mLooper(looper),
// 构造了一个DisplayEventReceiver,详见1.9.3
mReceiver(vsyncSource, eventRegistration, layerHandle),
mWaitingForVsync(false),
mLastVsyncCount(0),
mLastScheduleVsyncTime(0) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
1.9.3 DisplayEventReceiver构造
我们关注的mEventConnection就在这里初始化,就是通过SurfaceFlinger的binder接口createDisplayEventConnection拿到一个binder对象,除了返回binder对象,还返回了BitTube一侧的读写fd,后续端侧就可以通过这个BitTube和SurfaceFlinger通信,处理VSync相关的通知。
BitTube是对socketpair的封装,这里只要知道他可以用来跨进程通讯即可(会有两个fd,一个用来读一个用来写)。stealReceiveChannel方法将两个fd取出保存在mDataChannel中。
这里再提一下DisplayEventDispatcher::initialize方法,会把这里BitTube的fd添加到looper里。了解过Android的Looper机制就会直到,后续fd上如果有数据可读,就会自动回调LooperCallback的handleEvent。DisplayEventDispatcher继承了LooperCallback,这里传去的callback就是DisplayEventDispatcher,所以后续会回调DisplayEventDispatcher::handleEvent.
DisplayEventReceiver::DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource vsyncSource,
EventRegistrationFlags eventRegistration,
const sp<IBinder>& layerHandle) {
sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
if (sf != nullptr) {
mEventConnection = nullptr;
// 详见1.9.4
binder::Status status =
sf->createDisplayEventConnection(vsyncSource,
static_cast<
gui::ISurfaceComposer::EventRegistration>(
eventRegistration.get()),
layerHandle, &mEventConnection);
if (status.isOk() && mEventConnection != nullptr) {
mDataChannel = std::make_unique<gui::BitTube>();
将SurfaceFlinger返回的BitTube fd保存在mDataChannel中
status = mEventConnection->stealReceiveChannel(mDataChannel.get());
}
// 。。。
}
}
status_t DisplayEventDispatcher::initialize() {
// 。。。
if (mLooper != nullptr) {
// 添加上面BitTube的fd到Looper中,后续fd有信息就回调
int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
if (rc < 0) {
return UNKNOWN_ERROR;
}
}
return OK;
}
1.9.4 SurfaceFlinger::createDisplayEventConnection
调用了Scheduler的createDisplayEventConnection,Scheduler是SurfaceFlinger处理VSync信号的一重要的类,负责了VSync信号的产生,矫正等等。
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
gui::ISurfaceComposer::VsyncSource vsyncSource, EventRegistrationFlags eventRegistration,
const sp<IBinder>& layerHandle) {
const auto& handle =
vsyncSource == gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger
? mSfConnectionHandle
: mAppConnectionHandle;
// createDisplayEventConnection调用了createConnectionInternal
// 我们直接看createConnectionInternal,详见1.9.5
return mScheduler->createDisplayEventConnection(handle, eventRegistration, layerHandle);
}
1.9.5 Scheduler::createConnectionInternal
SurfaceFlinger有两个EventThread,分辨用来处理app-VSync和app-sf-VSync。(sf的VSync和app的Vsync不是同一个,有时候app也会需要使用sf的VSync,就是请求app-sf-VSync)
调用EventThread::createEventConnection来构造EventThreadConnection
sp<EventThreadConnection> Scheduler::createConnectionInternal(
EventThread* eventThread, EventRegistrationFlags eventRegistration,
const sp<IBinder>& layerHandle) {
int32_t layerId = static_cast<int32_t>(LayerHandle::getLayerId(layerHandle));
// createEventConnection就是直接构造EventThreadConnection
// 我们直接看EventThreadConnection构造函数,详见1.9.6
auto connection = eventThread->createEventConnection([&] { resync(); }, eventRegistration);
mLayerHistory.attachChoreographer(layerId, connection);
return connection;
}
1.9.6 EventThreadConnection构造
这里mChannel是BitTube,构造了一个BitTube用来后续的跨进程通信,同步VSync的消息。
EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid,
ResyncCallback resyncCallback,
EventRegistrationFlags eventRegistration)
// 这里的resyncCallback是上面传入的Scheduler::resync,后续请求VSync就是调用这个。
: resyncCallback(std::move(resyncCallback)),
mOwnerUid(callingUid),
mEventRegistration(eventRegistration),
mEventThread(eventThread),
mChannel(gui::BitTube::DefaultSize) {}
SurfaceFlinger处理app的VSync请求
2.1 EventThreadConnection::requestNextVsync
我们接着1.9,通过EventThreadConnection的binder调用requestNextVsync到SurfaceFlinger侧。
binder::Status EventThreadConnection::requestNextVsync() {
ATRACE_CALL();
// 调用EventThread::requestNextVsync,详见2.2
mEventThread->requestNextVsync(sp<EventThreadConnection>::fromExisting(this));
return binder::Status::ok();
}
2.2 EventThread::requestNextVsync
调用EventThreadConnection的resyncCallback,由1.9.6可知就是调用了Scheduler::resync
mCondition.notify_all唤醒EventThread去调度VSync信号。
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
// 由1.9.6可知这里的resyncCallback就是Scheduler::resync
if (connection->resyncCallback) {
// 调用Scheduler::resync,和模拟VSync信号矫正相关,如果想了解可以看5.1节
connection->resyncCallback();
}
if (connection->vsyncRequest == VSyncRequest::None) {
// 修改vsyncRequest的值,表示这个连接是需要响应下一次VSync的
connection->vsyncRequest = VSyncRequest::Single;
// 唤醒EventThread线程,详见2.3
mCondition.notify_all();
} else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {
connection->vsyncRequest = VSyncRequest::Single;
}
}
2.3 EventThread::threadMain
EventThread就是在threadMain循环处理VSync相关的事件,每次处理完事件后会mCondition.wait(lock),等待新的事件来临唤醒线程。
这里的真实的执行顺序一般是这样:
调用来mVsyncRegistration.schedule来请求下一个VSync,然后就在mCondition等着,等下一个VSync计时器时间触发,就会往mPendingEvents放一个VSync事件并且唤醒线程,线程进入下一次循环,开始筛选Consumer(调用过requestNextVsync的都是需要回调的Consumer,Consumer就是EventThreadConnection),然后把事件分发给需要回调的Consumer。
接下去我们来详细看下这个流程。
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
DisplayEventConsumers consumers;
// 循环处理VSync相关的事件
while (mState != State::Quit) {
std::optional<DisplayEventReceiver::Event> event;
// 从队列中获取下一个事件
if (!mPendingEvents.empty()) {
event = mPendingEvents.front();
mPendingEvents.pop_front();
// 如果是屏幕热插拔时间,重置mVSyncState,这个和软件模拟VSync逻辑有关
// 由于软件模拟VSync信号也是通过硬件VSync样本来预测的,如果屏幕发生热插拔,模拟数据自然需要重置
if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
if (event->hotplug.connected && !mVSyncState) {
mVSyncState.emplace(event->header.displayId);
} else if (!event->hotplug.connected && mVSyncState &&
mVSyncState->displayId == event->header.displayId) {
mVSyncState.reset();
}
}
}
bool vsyncRequested = false;
// 我们之前说过,client会调用surfaceFlinger的binder接口构造DisplayEventConnections
// 这里也通过DisplayEventConnections来鉴别哪些client需要响应下一次VSync
auto it = mDisplayEventConnections.begin();
while (it != mDisplayEventConnections.end()) {
if (const auto connection = it->promote()) {
// 判断这个连接是否需要相应下一次VSync
// 判断的核心逻辑就是根据vsyncRequest,2.2节我们看到requestNextVsync是会修改vsyncRequest的,就可以根据这个值判断是否需要响应下一个VSync
if (event && shouldConsumeEvent(*event, connection)) {
consumers.push_back(connection);
}
vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
++it;
} else {
it = mDisplayEventConnections.erase(it);
}
}
if (!consumers.empty()) {
// 给所有需要响应VSync的Connection分发事件。详见2.4
dispatchEvent(*event, consumers);
consumers.clear();
}
if (mVSyncState && vsyncRequested) {
mState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
} else {
ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
mState = State::Idle;
}
if (mState == State::VSync) {
// 主要就是通过这里来触发下一次VSync信号的。
// mVsyncRegistration.schedule会设置一个alarm,在下一个vsync的时候alarm会唤醒往mPendingEvents里面添加事件。详见2.3.1
const auto scheduleResult =
mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
.readyDuration = mReadyDuration.count(),
.earliestVsync = mLastVsyncCallbackTime.ns()});
LOG_ALWAYS_FATAL_IF(!scheduleResult, "Error scheduling callback");
} else {
mVsyncRegistration.cancel();
}
if (!mPendingEvents.empty()) {
continue;
}
// 等待在mCondition上,前面就是通过mCondition.notifyAll来唤醒的。
if (mState == State::Idle) {
mCondition.wait(lock);
} else {
// 。。。
}
}
mVsyncRegistration.cancel();
}
2.3.1 VSyncCallbackRegistration.schedule
在继续分析VSync分发之前,我们先来看看VSyncCallbackRegistration.schedule,这里是请求VSync信号的关键。
实际上调用了mDispatch->schedule,这个mDispatch是从VsyncSchedule::createDispatch方法构造的,是一个VSyncDispatchTimerQueue对象,所以这里就是调用来VSyncDispatchTimerQueue::schedule
ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
if (!mToken) {
return std::nullopt;
}
// 调用了mDispatch::schedule,这里的mDispatch是在EventThread构造函数构造VSyncCallbackRegistration时候传入的
// 最终可以看到mDispatch是一个VSyncDispatchTimerQueue,我们接下去看VSyncDispatchTimerQueue::schedule,详见2.3.2
return mDispatch->schedule(*mToken, scheduleTiming);
}
EventThread::EventThread(const char* name, std::shared_ptr<scheduler::VsyncSchedule> vsyncSchedule,
android::frametimeline::TokenManager* tokenManager,
ThrottleVsyncCallback throttleVsyncCallback,
GetVsyncPeriodFunction getVsyncPeriodFunction,
std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration)
: mThreadName(name),
mVsyncTracer(base::StringPrintf("VSYNC-%s", name), 0),
mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
mReadyDuration(readyDuration),
mVsyncSchedule(std::move(vsyncSchedule)),
// 可以看到mDispatch是从vsyncSchedule->getDispatch方法获取的
// VsyncSchedule是软件VSync模拟的核心类,dispatch是通过VsyncSchedule::createDispatch方法构造的
// 是一个VSyncDispatchTimerQueue对象,这里就不跟了,我们直接看VSyncDispatchTimerQueue::schedule,详见2.3.2
mVsyncRegistration(mVsyncSchedule->getDispatch(), createDispatchCallback(), name),
mTokenManager(tokenManager),
mThrottleVsyncCallback(std::move(throttleVsyncCallback)),
mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)) {
// 。。。
}
2.3.2 VSyncDispatchTimerQueue::schedule
加了锁后直接调用了scheduleLocked
ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
ScheduleTiming scheduleTiming) {
std::lock_guard lock(mMutex);
// 调用scheduleLocked,详见2.3.3
return scheduleLocked(token, scheduleTiming);
}
2.3.3 VSyncDispatchTimerQueue::scheduleLocked
这里的逻辑有一些难懂,首先我们要先搞清楚这里的mCallbacks为什么有多个,他们是和什么对应的。实际上是和EventThread相对应的,前面我们提过SurfaceFlinger会构造两个EventThread,一个是app的VSync节奏,一个是SurfaceFlinger的VSync节奏。
但是两个EventThread的VsyncSchedule实际用的是一个,他是和屏幕相关的,因为我们知道VSync信号其实是屏幕发出来的,即使是软件模拟的VSync信号也是参照屏幕的硬件VSync来模拟,所以这里VSyncDispatchTimerQueue和EventThread是一对多(一对二)的关系。
mIntendedWakeupTime记录的是当前alarm配置的时间,有三种可能,一个配置的是kInvalidTime(是int64最大值),另一个是app EventThread请求的下一次VSync时间,还一个是SurfaceFlinger请求的下一次VSync时间。
那么当now > mIntendedWakeupTime是什么情况呢,不会是kInvalidTime,因为他是最大值,每个alarm被触发回调后要不就会把mIntendedWakeupTime更新成下一次请求的VSync(如果有人请求的话),要不就是更新成kInvalidTime。所以now > mIntendedWakeupTime应该是由于时间误差mIntendedWakeupTime记录的这个时间的alarm还没有执行的情况。这种情况我们不需要重置alram,只需要通过addPendingWorkloadUpdate记录请求的下一次VSync时间。这次alarm触发后会根据addPendingWorkloadUpdate记录的时间来配置下一次alarm。
看完这个逻辑基本上也就能理解VSyncDispatchTimerQueue这里的思路了,剩下的逻辑看起来就简单多了。
ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
ScheduleTiming scheduleTiming) {
// 如果没有mCallbacks,直接返回。
auto it = mCallbacks.find(token);
if (it == mCallbacks.end()) {
return {};
}
auto& callback = it->second;
auto const now = mTimeKeeper->now();
// mIntendedWakeupTime记录的是当前定时器设定的时间
// 如果有Callback,并且now > mIntendedWakeupTime,说明定时器很快就会触发
auto const rearmImminent = now > mIntendedWakeupTime;
if (CC_UNLIKELY(rearmImminent)) {
// 这种情况就不重置计时器来,等待之前的计时器触发后再重置。
callback->addPendingWorkloadUpdate(scheduleTiming);
return getExpectedCallbackTime(*mTracker, now, scheduleTiming);
}
// 计算是否需要更新,这里callback是VSyncDispatchTimerQueueEntry的实例,详见2.3.3.1
const ScheduleResult result = callback->schedule(scheduleTiming, *mTracker, now);
if (!result.has_value()) {
return {};
}
// 如果计算出来的唤醒时间在mIntendedWakeupTime(本来计时器设定的)之前,那就要重新设计计时器
// wakeupTime()返回的是mArmedInfo里面的nextWakeupTime,在上面VSyncDispatchTimerQueueEntry::schedule计算出来的
if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
// 重置计时器,详见2.3.4
rearmTimerSkippingUpdateFor(now, it);
}
return result;
}
2.3.3.1 VSyncDispatchTimerQueueEntry::schedule
计算下一个VSync时间以及VSync唤醒时间。
timing.workDuration和timing.readyDuration是VSync的相位,我们现在已经知道有app的VSync和sf的VSync,其实这两种VSync都是基于hwc硬件VSync的基础上,加上一定相位差,然后软件模拟出来的。
这里tracker实际是一个VSyncPredictor对象,nextAnticipatedVSyncTimeFrom会根据传入参数来找到一个最接近传入参数时间的VSync点。关于VSyncPredictor逻辑我们后面再介绍。
adjustVsyncIfNeeded方法会判断新算出来的VSync时间是不是已经是触发过或者离上一个VSync时间太接近了,如果是就再他的基础上加一个VSync周期时间(60HZ就是16ms左右)
最后把算好的VSync时间和需要唤醒的时间放到mArmedInfo里。
ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
VSyncTracker& tracker, nsecs_t now) {
// 这里的tracker实际是一个VSyncPredictor,nextAnticipatedVSyncTimeFrom会根据入参找到附近的Vsync时间点
// VSyncPredictor内部的逻辑我们在后面将软件模拟VSync的原理时再来介绍,现在就当做黑盒即可。
auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
bool const wouldSkipAVsyncTarget =
mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
bool const wouldSkipAWakeup =
mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
return getExpectedCallbackTime(nextVsyncTime, timing);
}
// adjustVsyncIfNeeded调整时间的逻辑:如果拿到的nextVsyncTime离上一次太近或者是已经执行过的时间,就加一个VSync周期
nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
mScheduleTiming = timing;
// 存储算好的VSync时间到mArmedInfo
mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
return getExpectedCallbackTime(nextVsyncTime, timing);
}
2.3.4 VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor
重置定时器,wakeupTime是schedule计算出来的时间,PendingWorkloadUpdate是之前存储的唤醒时间,如果都没有则说明这个callback当前没有人请求VSync,否则就会调用update重新计算这个callback对应的下次VSync唤醒时间,但是入参callback因为我们刚刚计算过,所以不需要要调用update重新计算。
轮询callback找到一个最早的时间来做为定时器需要设置的时间,然后调用setTimer重置定时器。
void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
std::optional<nsecs_t> min;
std::optional<nsecs_t> targetVsync;
std::optional<std::string_view> nextWakeupName;
// 遍历所有callback,
for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
auto& callback = it->second;
// wakeupTime是schedule计算出来的时间,PendingWorkloadUpdate是之前存储的唤醒时间
if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
continue;
}
// 如果不是入参的callback,重新计算该callback的VSync(入参的callback才刚刚计算过,不需要重新计算)
if (it != skipUpdateIt) {
callback->update(*mTracker, now);
}
// 找到一个最早的时间
auto const wakeupTime = *callback->wakeupTime();
if (!min || *min > wakeupTime) {
nextWakeupName = callback->name();
min = wakeupTime;
targetVsync = callback->targetVsync();
}
}
// 如果最早的时间比之前设定的mIntendedWakeupTime早,就重新配置计时器。
if (min && min < mIntendedWakeupTime) {
if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
"us; VSYNC in ", ns2us(*targetVsync - now), "us");
ATRACE_NAME(trace.c_str());
}
// 重新配置计数器,详见2.3.5
setTimer(*min, now);
} else {
ATRACE_NAME("cancel timer");
cancelTimer();
}
}
2.3.5 VSyncDispatchTimerQueue::setTimer
TimeKeeper的本质就是对linux系统调用timerfd_settime进行封装,实现一个定时器的功能。这里就是根据之前计算的VSync时间设置一个定时器,定时器到了就回调timerCallback方法。
void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
mIntendedWakeupTime = targetTime;
// 这里TimeKeeper实际是调用linux的系统调用timerfd_settime来配置计时器,我们就不细看了。
// 等VSync时间到了,回调VSyncDispatchTimerQueue::timerCallback,详见2.3.6
mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
mIntendedWakeupTime);
mLastTimerSchedule = mTimeKeeper->now();
}
2.3.6 VSyncDispatchTimerQueue::timerCallback
这个方法主要的逻辑就是根据callback.wakeupTime来判断这个callback是否需要立刻回调。如果需要就封装到一个Invocation,再push到一个队列里,轮询回调。同时由于当前计时器已经触发,需要重新调用rearmTimerSkippingUpdateFor来确认是否需要配置下一个计时器。
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;
// 如果需要回调的wakeupTime一定不为空。
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));
// 根据wakeupTime判断这个callback是否需要回调,如果需要则封装到Invocation
if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
callback->executing();
invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
*wakeupTime, *readyTime});
}
}
mIntendedWakeupTime = kInvalidTime;
// 重置计时器,实际调用还是rearmTimerSkippingUpdateFor,详见之前2.3.4
rearmTimer(mTimeKeeper->now());
}
// 之前判断过需要当前触发的callback都封装存储到invocations,现在开始回调。
for (auto const& invocation : invocations) {
详见2.3.7
invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
invocation.deadlineTimestamp);
}
}
2.3.7 VSyncDispatchTimerQueueEntry::callback
这个mCallback是VSyncDispatchTimerQueueEntry构造时传入的。
这里的构造链路:
EventThread::onNewVsyncSchedule里构造VSyncCallbackRegistration
-》VSyncCallbackRegistration构造时构造了VSyncDispatchTimerQueueEntry
-》VSyncDispatchTimerQueueEntry构造传入了mCallback
由此我们也可以看出来,VSyncDispatchTimerQueue里面的callback其实是和EventThread一一关联的。
void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
nsecs_t deadlineTimestamp) {
{
std::lock_guard<std::mutex> lk(mRunningMutex);
mRunning = true;
}
// 这个mCallback是VSyncDispatchTimerQueueEntry构造时传入的。
// 这里的构造链路是EventThread::onNewVsyncSchedule里构造VSyncCallbackRegistration
// VSyncCallbackRegistration构造时构造了VSyncDispatchTimerQueueEntry
// VSyncDispatchTimerQueueEntry构造传入了mCallback
mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
std::lock_guard<std::mutex> lk(mRunningMutex);
mRunning = false;
mCv.notify_all();
}
scheduler::VSyncCallbackRegistration EventThread::onNewVsyncScheduleInternal(
std::shared_ptr<scheduler::VsyncSchedule> schedule) {
// 。。。
auto oldRegistration =
std::exchange(mVsyncRegistration,
scheduler::VSyncCallbackRegistration(mVsyncSchedule->getDispatch(),
// mCallback就是createDispatchCallback,详见2.3.8
createDispatchCallback(),
mThreadName));
// 。。。
return oldRegistration;
}
2.3.8 EventThread::createDispatchCallback()
mCallback其实就是回调EventThread::onVsync
scheduler::VSyncDispatch::Callback EventThread::createDispatchCallback() {
return [this](nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
// 所以2.3.7 的mCallback就是回调EventThread::onVsync,详见2.3.9
onVsync(vsyncTime, wakeupTime, readyTime);
};
}
2.3.9 EventThread::onVsync
构造一个VSync的Event,放在mPendingEvents队列里,然后唤醒2.3 EventThread::threadMain来处理这个事件,到此我们就介绍完了一个VSync信号是怎么产生的。接下去我们看下分发回应用的逻辑。
void EventThread::onVsync(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
std::lock_guard<std::mutex> lock(mMutex);
mLastVsyncCallbackTime = TimePoint::fromNs(vsyncTime);
LOG_FATAL_IF(!mVSyncState);
mVsyncTracer = (mVsyncTracer + 1) % 2;
// 构造了一个VSync事件,放在mPendingEvents
mPendingEvents.push_back(makeVSync(mVSyncState->displayId, wakeupTime, ++mVSyncState->count,
vsyncTime, readyTime));
// 唤醒2.3 EventThread::threadMain来处理这个事件。
mCondition.notify_all();
}
2.4 EventThread::dispatchEvent
我们接着2.3 threadMain里面调用dispatchEvent来分发VSync事件的逻辑继续看。
由2.3我们可以知道这里consumers都是调用过requestNextVSync的EventThreadConnection。
void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
const DisplayEventConsumers& consumers) {
for (const auto& consumer : consumers) {
DisplayEventReceiver::Event copy = event;
// 。。。
// 调用postEvent分发事件,详见2.5
switch (consumer->postEvent(copy)) {
// 。。。
}
}
}
2.5 EventThreadConnection::postEvent
通过BitTube通道发送事件
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
// 。。。
// 通过BitTube通道发送事件。
auto size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return toStatus(size);
}
2.6 DisplayEventDispatcher::handleEvent
之前在1.9.3有提到过,我们把Bitube的fd通过mLooper->addFd加到looper里,这样当fd消息就会回调DisplayEventDispatcher::handleEvent
processPendingEvents里面会调用mReceiver.getEvents来获取2.5节通过BitTube传过来的字节流,并且构建一个Events.
然后调用dispatchVsync来分发VSync事件。
int DisplayEventDispatcher::handleEvent(int, int events, void*) {
// 。。。
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
VsyncEventData vsyncEventData;
// 调用mReceiver.getEvents,将BitTube的字节流封装成Event
if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
// 。。。
mWaitingForVsync = false;
mLastVsyncCount = vsyncCount;
// 分发事件,详见2.7
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
}
// 等待超时则直接分发一个空的Event VSync
if (mWaitingForVsync) {
const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime;
if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) {
ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
mWaitingForVsync = false;
dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
++mLastVsyncCount, vsyncEventData /* empty data */);
}
}
return 1; // keep the callback
}
2.7 NativeDisplayEventReceiver::dispatchVsync
这里DisplayEventDispatcher实际是NativeDisplayEventReceiver,前面初始化的时候介绍过,所以这里实际调用来NativeDisplayEventReceiver::dispatchVsync
这里是jni回调回java层,调用DisplayEventReceiver的dispatchVsync
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
uint32_t count, VsyncEventData vsyncEventData) {
// 。。。
if (receiverObj.get() && vsyncEventDataObj.get()) {
// 。。。
// jni反向调用java层,调用DisplayEventReceiver的dispatchVsync,详见2.8
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
timestamp, displayId.value, count);
ALOGV(“receiver %p ~ Returned from vsync handler.”, this);
}
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}
2.8 DisplayEventReceiver.dispatchVsync
调用了onVsync,前面介绍过,这里的DisplayEventReceiver实际是FrameDisplayEventReceiver,所以回调的是Chreographer的内部类FrameDisplayEventReceiver的onVsync
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
onVsync(timestampNanos, physicalDisplayId, frame, mVsyncEventData);
}
2.9 FrameDisplayEventReceiver.onVsync
发送了一个MSG_DO_FRAME消息,这里没有配置message.what,但是MSG_DO_FRAME的实际值就是0,所以没有配置消息类型默认就是MSG_DO_FRAME。mHandler是FrameHandler的实例。
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
try {
// 。。。
mTimestampNanos = timestampNanos;
mFrame = frame;
mLastVsyncEventData.copyFrom(vsyncEventData);
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
// 发送了一个MSG_DO_FRAME消息,FrameHandler处理,详见2.10
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
2.10 FrameHandler.handleMessage
调用了doFrame
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
//详见2.11
doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData());
break;
// 。。。
}
}
2.11 Choreographer.doFrame
这里doCallbacks中type为CALLBACK_TRAVERSAL的回调是mTraversalRunnable,链路太长来可能忘记来,我们回头看看1.3节,这个callback是在1.3节配置的。
mTraversalRunnable在ViewRootImpl里,里面会执行ViewRootImpl.doTraversal,后面就不展开将来,和本章内容关系不大,做过应用开发的可能知道doTraversal会执行View的测量,布局,绘制等,这样应用侧的请求Vsync信号的流程的我们就讲解完了,接下去看一下SurfaceFlinger侧。
void doFrame(long frameTimeNanos, int frame,
DisplayEventReceiver.VsyncEventData vsyncEventData) {
final long startNanos;
final long frameIntervalNanos = vsyncEventData.frameInterval;
boolean resynced = false;
try {
// 。。。处理VsyncEventData里面的数据,封装到FrameInfo
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos);
mFrameInfo.markPerformTraversalsStart();
// 主要是这里的回调,大家回头看看1.3节,之前配置的CALLBACK_TRAVERSAL类型的callback
// 这里的callback是mTraversalRunnable
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos);
} finally {
AnimationUtils.unlockAnimationClock();
if (resynced) {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
// 。。。
}
SurfaceFlinger请求VSync
我们之前在介绍BlastBufferQueue那个章节的时候提到过,无论是内容变化还是窗口属性变化,都会通过Transaction.apply来同步给SurfaceFlinger,而SurfaceFlinger在处理变化后都会调用SurfaceFlinger::setTransactionFlags,记录需要重新做合成,这时候就会去请求VSync信号,我们就从这里开始看。
这个流程总体比较简单,相对复杂的部分和上面app的请求VSync是一样的。
3.1 SurfaceFlinger::setTransactionFlags
调用scheduleCommit来请求下一个VSync,这个VSync是SurfaceFlinger用来合成图层的。
void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
const sp<IBinder>& applyToken, FrameHint frameHint) {
mScheduler->modulateVsync({}, &VsyncModulator::setTransactionSchedule, schedule, applyToken);
uint32_t transactionFlags = mTransactionFlags.fetch_or(mask);
ATRACE_INT("mTransactionFlags", transactionFlags);
if (const bool scheduled = transactionFlags & mask; !scheduled) {
// 调用scheduleCommit来请求下一个VSync,详见3.2
scheduleCommit(frameHint);
} else if (frameHint == FrameHint::kActive) {
mScheduler->resetIdleTimer();
}
}
3.2 SurfaceFlinger::scheduleCommit
调用Scheduler::scheduleFrame,我们之前说过VSync的调用都是由Schduler来处理的,这里也是调用Srchduler的方法
void SurfaceFlinger::scheduleCommit(FrameHint hint) {
if (hint == FrameHint::kActive) {
mScheduler->resetIdleTimer();
}
mPowerAdvisor->notifyDisplayUpdateImminentAndCpuReset();
// 调用Scheduler::scheduleFrame,详见3.3
mScheduler->scheduleFrame();
}
3.3 MessageQueue::scheduleFrame
Scheduler继承自MessageQueue,所以这里实际执行的是MessageQueue::scheduleFrame
mVsync.registration->schedule是不是看着很眼熟,2.3.1已经讲过这个逻辑了,最终他会回调VSyncCallbackRegistration内部的mCallback,我们往下来看看这里的mCallback是哪里传入的
void MessageQueue::scheduleFrame() {
ATRACE_CALL();
std::lock_guard lock(mVsync.mutex);
// 前面已经介绍过了,这里的逻辑和app请求是一样的。
mVsync.scheduledFrameTime =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.earliestVsync = mVsync.lastCallbackTime.ns()});
}
3.4 MessageQueue::onNewVsyncScheduleLocked
这里的链路实际是在Scheduler初始化时,调用initVsync->onNewVsyncSchedule->onNewVsyncScheduleLocked,但是我们不关注这些,直接来看传入mCallback的地方MessageQueue::onNewVsyncScheduleLocked。
可以看到最终回调方法是MessageQueue::vsyncCallback
std::unique_ptr<scheduler::VSyncCallbackRegistration> MessageQueue::onNewVsyncScheduleLocked(
std::shared_ptr<scheduler::VSyncDispatch> dispatch) {
const bool reschedule = mVsync.registration &&
mVsync.registration->cancel() == scheduler::CancelResult::Cancelled;
auto oldRegistration = std::move(mVsync.registration);
mVsync.registration = std::make_unique<
scheduler::VSyncCallbackRegistration>(std::move(dispatch),
// MessageQueue::vsyncCallback是传入的回调,详见3.5
std::bind(&MessageQueue::vsyncCallback, this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3),
"sf");
if (reschedule) {
mVsync.scheduledFrameTime =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.earliestVsync = mVsync.lastCallbackTime.ns()});
}
return oldRegistration;
}
3.5 MessageQueue::vsyncCallback
封装来一下VSync的参数,调用了Handler::dispatchFrame
void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
ATRACE_CALL();
// Trace VSYNC-sf
mVsync.value = (mVsync.value + 1) % 2;
const auto expectedVsyncTime = TimePoint::fromNs(vsyncTime);
{
std::lock_guard lock(mVsync.mutex);
mVsync.lastCallbackTime = expectedVsyncTime;
mVsync.scheduledFrameTime.reset();
}
const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions(
{targetWakeupTime, readyTime, vsyncTime})};
// 详见3.6
mHandler->dispatchFrame(vsyncId, expectedVsyncTime);
}
3.6 MessageQueue::Handler::dispatchFrame
post了一个消息,我们来看handleMessage处理消息的地方。
void MessageQueue::Handler::dispatchFrame(VsyncId vsyncId, TimePoint expectedVsyncTime) {
if (!mFramePending.exchange(true)) {
mVsyncId = vsyncId;
mExpectedVsyncTime = expectedVsyncTime;
// 往looper里发送来一个消息,在handleMessage处理,详见3.7
mQueue.mLooper->sendMessage(sp<MessageHandler>::fromExisting(this), Message());
}
}
3.7 MessageQueue::Handler::handleMessage
调用MessageQueue::onFrameSignal,这里的MessageQueue是Scheduler实例,所以调用的是Scheduler::onFrameSignal
void MessageQueue::Handler::handleMessage(const Message&) {
mFramePending.store(false);
// 详见3.8
mQueue.onFrameSignal(mQueue.mCompositor, mVsyncId, mExpectedVsyncTime);
}
3.8 Scheduler::onFrameSignal
到这里SurfaceFlinger就收到了VSync,并且开始处理了,SurfaceFlinger收到VSync信号主要做的处理就是合成surface。
void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
TimePoint expectedVsyncTime) {
const TimePoint frameTime = SchedulerClock::now();
// 做合成的一些预处理,判断flag决策是否需要合成
if (!compositor.commit(frameTime, vsyncId, expectedVsyncTime)) {
return;
}
// 触发合成。
compositor.composite(frameTime, vsyncId);
compositor.sample();
}
软件模拟VSync信号的计算以及矫正
我们在2.3.3.1节提到过,使用的VSync是软件模拟,通过VSyncPredictor::nextAnticipatedVSyncTimeFrom来预测的,实际上软件VSync的模拟也是离不开硬件VSync的样本。接下来我们来介绍一下软件VSync模拟以及矫正的逻辑。
大家可能会有点疑惑,觉得软件模拟VSync不是很简单吗,怎么会有这么复杂的逻辑,直接搞一个计时器,60HZ就弄一个16.666~ms的计时器不就行了。其实这样是不准确的,首先定时器的接口提供的能力本身就不一定准确,加上我们需要收到定时器后再去配置下一个定时器,代码执行也需要一些时间,所以就会造成不小的误差。
而这里模拟的思路就是我们根据HWC硬件提供的VSync样本来计算软件需要的间隔时间,也就是说,可能60HZ的时候,我们算出来定时器是15ms一次(只是打个比方)。
我们先从VSyncPredictor::nextAnticipatedVSyncTimeFrom入手来分析。
4.1 VSyncPredictor::nextAnticipatedVSyncTimeFrom
我们之前提过这个方法的作用,传入的参数是一个时间点,返回最靠近这个时间点的VSync信号的时间戳。
nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const {
std::lock_guard lock(mMutex);
// 根据现在的模型获取下一个VSync,详见4.2
mLastVsyncSequence = getVsyncSequenceLocked(timePoint);
const auto renderRatePhase = [&]() REQUIRES(mMutex) -> int {
if (!mRenderRate) return 0;
const auto divisor =
RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod),
*mRenderRate);
if (divisor <= 1) return 0;
const int mod = mLastVsyncSequence->seq % divisor;
if (mod == 0) return 0;
return divisor - mod;
}();
// 正常直接返回算好的VSync,否则是当屏幕的刷新率比渲染率快很多时候的处理。
if (renderRatePhase == 0) {
return mLastVsyncSequence->vsyncTime;
}
auto const [slope, intercept] = getVSyncPredictionModelLocked();
const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * renderRatePhase;
return nextAnticipatedVSyncTimeFromLocked(approximateNextVsync - slope / 2);
}
4.2 VSyncPredictor::getVsyncSequenceLocked
通过nextAnticipatedVSyncTimeFromLocked获取下一个VSync时间,并且根据返回的VSync时间算VSync的序列号。
auto VSyncPredictor::getVsyncSequenceLocked(nsecs_t timestamp) const -> VsyncSequence {
// 通过nextAnticipatedVSyncTimeFromLocked获取下一个VSync时间,详见4.3
const auto vsync = nextAnticipatedVSyncTimeFromLocked(timestamp);
if (!mLastVsyncSequence) return {vsync, 0};
// VsyncSequence是VSync的序列号,表示他是第几个VSync,这里的计算很简单就不说了。
const auto [slope, _] = getVSyncPredictionModelLocked();
const auto [lastVsyncTime, lastVsyncSequence] = *mLastVsyncSequence;
const auto vsyncSequence = lastVsyncSequence +
static_cast<int64_t>(std::round((vsync - lastVsyncTime) / static_cast<float>(slope)));
return {vsync, vsyncSequence};
}
4.3 VSyncPredictor::nextAnticipatedVSyncTimeFromLocked
这里分两种模式:
1.样本集为空的情况,这种情况就是根据第一个点加上n个VSync周期(大于timePonit的最小值)作为下一个VSync.
2.第二种情况是有足够的硬件VSync样本,那么会通过硬件VSync样本来计算一个模型,其实就是一条直线:y = slope * x + intercept。然后计算这个直线上,timePonit作为y,获得x,然后取大于x的最小整数,带入直线再算出y,作为下一个VSync信号的时间戳,说的有一些绕口,但是实际很简单,就是初中的数学知识。
接下去我们要看看是怎么计算出这个模型[slope, intercept]的,详见4.4 VSyncPredictor::addVsyncTimestamp
nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const {
// 获取一个Model,这个model其实就是两个数值,slope斜率和intercept偏移。
// 有这两个值就可以确定一条直线,而这个直线就是VSync预测函数。
// 这两个值是通过硬件VSync样本点来计算出来的
auto const [slope, intercept] = getVSyncPredictionModelLocked();
// mTimestamps是样本集,一般是硬件VSync时间点
// 如果现在样本是空的,那么就没法确定model这条直线,这个时候直接来算下一个VSync时间
if (mTimestamps.empty()) {
// mKnownTimestamp记录第一个样本点,如果有一个样本点,就一这个样本点来计算
// 如果一个样本点都没有,就把入参当做第一个样本点时间
auto const knownTimestamp = mKnownTimestamp ? *mKnownTimestamp : timePoint;
// mIdealPeriod是刷新周期,比如当前刷新率如果是60HZ就是16.6ms
// 计算得到的numPeriodsOut就是timePoint后面一个VSync距离第一个样本点的周期数
auto const numPeriodsOut = ((timePoint - knownTimestamp) / mIdealPeriod) + 1;
// 直接以第一个样本时间+(上面计算出来的下一个VSync距离第一个样本周期数*单个周期的时间)来计算下一个VSync
return knownTimestamp + numPeriodsOut * mIdealPeriod;
}
// 获取样本点里最早的
auto const oldest = *std::min_element(mTimestamps.begin(), mTimestamps.end());
// 这里就是通过简单的数据计算,基于前面斜率,intercept偏移确定的直线来确定下一个VSync时间点
// 这里我举个具体的数字例子更容易讲清楚,假如我们的模型斜率是16,偏移是1。
// 那么就是y = 16x + 1,第一个VSync时间就是1,第二个就是17,假如timePoint传入的是10,那么计算出来的下一个VSync就是17。
auto const zeroPoint = oldest + intercept;
auto const ordinalRequest = (timePoint - zeroPoint + slope) / slope;
auto const prediction = (ordinalRequest * slope) + intercept + oldest;
// 。。。日志打印
return prediction;
}
4.4 VSyncPredictor::addVsyncTimestamp
这个方法的入口是我们在后面会讲,如果感兴趣可以看5.1节。 核心逻辑就是app请求VSync时候,如果发现上一次硬件校准时间超过750ms了,就会触发硬件校准,到HWC去注册硬件VSync。
这里计算直线模型的算法是一元线性回归,我们就不详细看代码了,google给出计算公式的注释。
bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) {
std::lock_guard lock(mMutex);
if (!validate(timestamp)) {
// 如果是无效的timestamp(和之前样本模型误差很大),就清空样本集
if (mTimestamps.size() < kMinimumSamplesForPrediction) {
mTimestamps.push_back(timestamp);
clearTimestamps();
} else if (!mTimestamps.empty()) {
mKnownTimestamp =
std::max(timestamp, *std::max_element(mTimestamps.begin(), mTimestamps.end()));
} else {
mKnownTimestamp = timestamp;
}
return false;
}
// 添加样本集
if (mTimestamps.size() != kHistorySize) {
mTimestamps.push_back(timestamp);
mLastTimestampIndex = next(mLastTimestampIndex);
} else {
mLastTimestampIndex = next(mLastTimestampIndex);
mTimestamps[mLastTimestampIndex] = timestamp;
}
traceInt64If("VSP-ts", timestamp);
const size_t numSamples = mTimestamps.size();
// 如果样本集数量不够,就不计算模型参数
if (numSamples < kMinimumSamplesForPrediction) {
mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
return true;
}
// This is a 'simple linear regression' calculation of Y over X, with Y being the
// vsync timestamps, and X being the ordinal of vsync count.
// The calculated slope is the vsync period.
// Formula for reference:
// Sigma_i: means sum over all timestamps.
// mean(variable): statistical mean of variable.
// X: snapped ordinal of the timestamp
// Y: vsync timestamp
//
// Sigma_i( (X_i - mean(X)) * (Y_i - mean(Y) )
// slope = -------------------------------------------
// Sigma_i ( X_i - mean(X) ) ^ 2
//
// intercept = mean(Y) - slope * mean(X)
//
// 。。。计算模型
// 这里就不看计算逻辑了,google给了我们注释,上面的公式就是计算模型的算法
// 有数学基础的话就能看出来这个是一个一元线性回归,思路就是找出一条线,尽量和我们的样本点拟合。
// slope是斜率,intercept是偏移。
return true;
}
其他(硬件VSync的触发流程/矫正的触发点)
硬件VSync的流程因为涉及HWC,很多细节不同平台也会不一样,而且总体也不复杂,我们不会介绍的那么详细,主要带了解一下大体的流程和思路。
回看一下2.2节,我们之前在app请求VSync信号的流程中提到来中间会调用Schduler::resync这个方法,这个就是校准用的,我们就从这里开始看
5.1 Scheduler::resync
判断距离上次校准时间是否超过750ms,如果超过就调用resyncAllToHardwareVsync再次进行校准。
void Scheduler::resync() {
static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
const nsecs_t now = systemTime();
const nsecs_t last = mLastResyncTime.exchange(now);
// 只有上次校准间隔750ms以上才会再次校准
if (now - last > kIgnoreDelay) {
// 详见5.2
resyncAllToHardwareVsync(false /* allowToEnable */);
}
}
5.2 resyncAllToHardwareVsync
void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) {
ATRACE_CALL();
std::scoped_lock lock(mDisplayLock);
ftl::FakeGuard guard(kMainThreadContext);
// 遍历mDisplays,调用resyncToHardwareVsyncLocked
// 因为这里校准的依据是硬件VSync信号,不同屏幕可能是不同的硬件环境,详见5.3
for (const auto& [id, _] : mDisplays) {
resyncToHardwareVsyncLocked(id, allowToEnable);
}
}
5.3 Scheduler::resyncToHardwareVsyncLocked
这里hw VSync有三种状态:
- Enabled 当前hwVSyncz正在工作
- Disabled 当前没有打开hwVSync(目前不在校准,可以通过enableHardwareVsync来enable)
- Disallowed 不允许使用hwVSync,因为屏幕是灭屏状态
调用isHardwareVsyncAllowed判断状态是否处在Disallowed,只要不是Disallowed状态就继续校准流程。
startPeriodTransition传入的参数mSchedulerCallback是Scheduler构造时传入的,后面hw VSync回来之后会调用,后面再看。
void Scheduler::resyncToHardwareVsyncLocked(PhysicalDisplayId id, bool allowToEnable,
std::optional<Fps> refreshRate) {
const auto displayOpt = mDisplays.get(id);
if (!displayOpt) {
ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
return;
}
const Display& display = *displayOpt;
// 判断硬件VSync状态,只要不是Disallowed就返回ture(如果参数是ture,会把状态从Disallowed改成Disabled)
if (display.schedulePtr->isHardwareVsyncAllowed(allowToEnable)) {
if (!refreshRate) {
refreshRate = display.selectorPtr->getActiveMode().modePtr->getFps();
}
if (refreshRate->isValid()) {
// 这里的mSchedulerCallback是构建Scheduler时传入的,实际是SurfaceFlinger对象, 后面hwVSync信号回来会回调
// schdulerPtr是VsyncSchedule,详见5.4
display.schedulePtr->startPeriodTransition(mSchedulerCallback, refreshRate->getPeriod(),
false /* force */);
}
}
}
5.4 VsyncSchedule::startPeriodTransition
startPeriodTransition主要是根据周期是否变化以及入参force来修改mMoreSamplesNeeded变量,同时会判断是否需要清空mUnfiredFences列表,这里列表里面存的是一些Fence,这里是另一个校准入口,我们只顺带提一下,在每次postComposition提交layer合成后,会去hwc拿一个Fence,然后通过这个Fence的时间来验证我们的软件模拟VSync模型是否准确,如果不准确也会触发校准逻辑。这里感兴趣的话自己去看一下,我们就不介绍了。
这个方法核心是调用enableHardwareVsyncLocked来使能hwVsync
void VsyncSchedule::startPeriodTransition(ISchedulerCallback& callback, Period period, bool force) {
std::lock_guard<std::mutex> lock(mHwVsyncLock);
// 主要是根据周期是否变化以及入参force来修改mMoreSamplesNeeded变量
mController->startPeriodTransition(period.ns(), force);
// 使能hw VSync,详见 5.5
enableHardwareVsyncLocked(callback);
}
5.5 syncSchedule::enableHardwareVsyncLocked
主要就是调用了SurfaceFlinger::setVsyncEnabled使能VSync
void VsyncSchedule::enableHardwareVsyncLocked(ISchedulerCallback& callback) {
if (mHwVsyncState == HwVsyncState::Disabled) {
// 本来如果是Disabled,说明我们刚开始校准模型,把之前的模型reset掉。
getTracker().resetModel();
// 前面说过这个callback实际是SurfaceFlinger,这里就是调用SurfaceFlinger::setVsyncEnabled,详见5.6
callback.setVsyncEnabled(mId, true);
mHwVsyncState = HwVsyncState::Enabled;
}
}
5.6 SurfaceFlinger::setVsyncEnabled
主要是调用了setHWCVsyncEnabled使能VSync
void SurfaceFlinger::setVsyncEnabled(PhysicalDisplayId id, bool enabled) {
static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
// 。。。
if (const auto display = getDisplayDeviceLocked(id); display && display->isPoweredOn()) {
// 详见5.7
setHWCVsyncEnabled(id, enabled);
}
}));
}
5.7 SurfaceFlinger::setHWCVsyncEnabled
这里的getHwComposer返回的值是在SurfaceFlinger::init初始化的,其实是一个aidl的client端,SurfaceFlinger借助这个Cilent和HWC进行通信。
setVsyncEnabled是binder调用,调用到来HWC侧。
void setHWCVsyncEnabled(PhysicalDisplayId id, bool enabled) {
hal::Vsync halState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE;
// 我们先来看看getHwComposer()是什么,详见5.7.1
// setVsyncEnabled见5.8
getHwComposer().setVsyncEnabled(id, halState);
}
5.7.1 SurfaceFlinger::init()
void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
// 。。。
// 这里只列了相关代码,上面getHwComposer()的结果就是这里构造的
// 详见5.7.2
mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName));
// 这里还注册来HWC的回调,后面HWC想要通知SurfaceFlinger就是通过这个Callback.
// 这个Callback传的this,就是SurfaceFlinger
mCompositionEngine->getHwComposer().setCallback(*this);
// 。。。
}
5.7.2 DefaultFactory::createHWComposer
调用了Hwc2::Composer::create构造Composer
std::unique_ptr<HWComposer> DefaultFactory::createHWComposer(const std::string& serviceName) {
return std::make_unique<android::impl::HWComposer>(serviceName);
}
HWComposer::HWComposer(const std::string& composerServiceName)
// 详见5.7.3
: HWComposer(Hwc2::Composer::create(composerServiceName)) {}
5.7.3 Composer::create
旧版本的Android用的hidl和底层hal通信(HWC),但是新版本的Android也换成aidl了。这里通过serviceName去ServiceManager里面拿到hwc binder的handle,后续就可以跟hwc进行binder通信了。
std::unique_ptr<Composer> Composer::create(const std::string& serviceName) {
if (AidlComposer::isDeclared(serviceName)) {
return std::make_unique<AidlComposer>(serviceName);
}
return std::make_unique<HidlComposer>(serviceName);
}
5.8 AidlComposer::setVsyncEnabled
我们接着5.7来看setVsyncEnabled
这里相关的aidl定义在/hardware/interfaces/graphics/composer/aidl/android/hardware/graphics/composer3路径下
真正的实现在/hardware/google/graphics/commom/hwc3下。
因为这里的操作和硬件关联较大,所以最终实现不同平台差异较大,我们就只简单看一下谷歌aosp的流程。
Error AidlComposer::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
const bool enableVsync = enabled == IComposerClient::Vsync::ENABLE;
// binder调用,详见5.9
const auto status =
mAidlComposerClient->setVsyncEnabled(translate<int64_t>(display), enableVsync);
// 。。。
return Error::NONE;
}
5.9 ComposerClient::setVsyncEnabled
调用mHal的setVsyncEnabled,这里mHal是IComposerHal接口,也是个binder,在aosp中他的实现类是HalImpl
ndk::ScopedAStatus ComposerClient::setVsyncEnabled(int64_t display, bool enabled) {
DEBUG_DISPLAY_FUNC(display);
// 这里的mHal是IComposerHal,详见5.10
auto err = mHal->setVsyncEnabled(display, enabled);
return TO_BINDER_STATUS(err);
}
5.10 HalImpl::setVsyncEnabled
这里我们已经在Composer services里面了,而不是在SurfaceFlinger进程里。
int32_t HalImpl::setVsyncEnabled(int64_t display, bool enabled) {
ExynosDisplay* halDisplay;
RET_IF_ERR(getHalDisplay(display, halDisplay));
hwc2_vsync_t hwcEnable;
a2h::translate(enabled, hwcEnable);
// halDisplay有很几种类型,但是最终都是继承自是ExynosDisplay实例,详见5.11
return halDisplay->setVsyncEnabled(hwcEnable);
}
5.11 ExynosDisplay::setVsyncEnabled
mDisplayInterface是ExynosDisplayInterface或者继承他的某个子类,我们这里以ExynosDisplayDrmInterface为例进行介绍。
从这个名字可以看出他和drm有关系,新版本的Android现在的UI驱动架构都是基于linux的drm架构来实现的。目前我们不会对drm做过多介绍(本人水平有限),如果后面有时间
int32_t ExynosDisplay::setVsyncEnabled(
int32_t /*hwc2_vsync_t*/ enabled) {
Mutex::Autolock lock(mDisplayMutex);
return setVsyncEnabledInternal(enabled);
}
int32_t ExynosDisplay::setVsyncEnabledInternal(
int32_t enabled) {
// 。。。
// 核心流程在这里,mDisplayInterface的是ExynosDisplayInterface或者继承他的某个子类
// 我们这里以ExynosDisplayDrmInterface为例进行介绍
if (mDisplayInterface->setVsyncEnabled(val) < 0) {
HWC_LOGE(this, "vsync ioctl failed errno : %d", errno);
return HWC2_ERROR_BAD_DISPLAY;
}
mVsyncState = (hwc2_vsync_t)enabled;
return HWC2_ERROR_NONE;
}
5.12 ExynosDisplayDrmInterface::setVsyncEnabled
int32_t ExynosDisplayDrmInterface::setVsyncEnabled(uint32_t enabled)
{
if (enabled == HWC2_VSYNC_ENABLE) {
// 使能VSyncWorker,详见5.13
mDrmVSyncWorker.VSyncControl(true);
} else {
if (mVsyncCallback.getDesiredVsyncPeriod() == 0)
mDrmVSyncWorker.VSyncControl(false);
}
// 回调通知VSync使能状态变化,这里我们不关心
mVsyncCallback.enableVSync(HWC2_VSYNC_ENABLE == enabled);
// 。。。
return NO_ERROR;
}
5.13 VSyncWorker::VSyncControl
设置enable位,然后唤醒在cond_等待的线程,每个VSyncWork都会启一个线程然后循环执行VSyncWorker::Routine方法,然后如果之前enable是false,就会在cond_上等待唤醒。
void VSyncWorker::VSyncControl(bool enabled) {
Lock();
// 配置变量enabled
enabled_ = enabled;
last_timestamp_ = -1;
Unlock();
// 唤醒等待在cond_上的线程。
// 这里VSyncWorker其实是一个线程循环执行Routine方法,这个线程会在cond_上挂起
// 接下来我们来分析一下Routine这个方法,详见5.14
Signal();
}
void Signal() {
cond_.notify_all();
}
5.14 VSyncWorker::Routine
这个方法看着有点长,其实逻辑很简单,未使能的情况会在WaitForSignalOrExitLocked上等待,然后一直等到上面使能VSync的时候Signal之后唤醒。然后后面会通过drm的接口,等待硬件VSync信号。
硬件VSync信号来之后就调用callback_回调。
void VSyncWorker::Routine() {
int ret = 0;
Lock();
if (!enabled_) {
// 如果是unabled状态,会在这里等待,实际是等待在cond_上,我们上面看到使能VSync就会唤醒这里。
ret = WaitForSignalOrExitLocked();
if (ret == -EINTR) {
Unlock();
return;
}
}
// 。。。
if (pipe != nullptr) {
uint32_t high_crtc = (pipe->crtc->Get()->GetIndexInResArray()
<< DRM_VBLANK_HIGH_CRTC_SHIFT);
vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
(high_crtc &
DRM_VBLANK_HIGH_CRTC_MASK));
vblank.request.sequence = 1;
// 这个方法就是等待DRM的VSync时间
// 关于DRM我们就不深入了
ret = drmWaitVBlank(pipe->device->GetFd(), &vblank);
if (ret == -EINTR)
return;
}
if (ret) {
ret = SyntheticWaitVBlank(×tamp);
if (ret)
return;
} else {
timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs +
(int64_t)vblank.reply.tval_usec * 1000;
}
if (!enabled_)
return;
if (callback_) {
// 回调callback_,这里的callback_是VsyncCallback,在我们这个流程里实际是ExynosDisplayDrmInterface,详见5.15
callback_(timestamp);
}
last_timestamp_ = timestamp;
}
5.15 ExynosDisplayDrmInterface::Callback
void ExynosDisplayDrmInterface::Callback(
int display, int64_t timestamp)
{
// 。。。
// 我们只看我们关注的部分
exynosDevice->onVsync(mExynosDisplay->mDisplayId, timestamp);
}
5.16 ExynosDevice::onVsync
这里的mCallbackInfos里面是SurfaceFlinger通过binder注册的callback,所以这里会回调回SurfaceFlinger
void ExynosDevice::onVsync(uint32_t displayId, int64_t timestamp) {
Mutex::Autolock lock(mDeviceCallbackMutex);
if (!isCallbackRegisteredLocked(HWC2_CALLBACK_VSYNC)) return;
hwc2_callback_data_t callbackData = mCallbackInfos[HWC2_CALLBACK_VSYNC].callbackData;
// 这里的callback实际是5.7.1 在SurfaceFlinger通过binder注册的
// 最终会回调回SurfaceFlinger,SurfaceFlinger的回调详见5.17
HWC2_PFN_VSYNC callbackFunc =
reinterpret_cast<HWC2_PFN_VSYNC>(mCallbackInfos[HWC2_CALLBACK_VSYNC].funcPointer);
callbackFunc(callbackData, displayId, timestamp);
}
5.17 SurfaceFlinger::onComposerHalVsync
前面说过,注册的Callback就是SurfaceFlinger自身,硬件VSync会回调到这里,这里会调用mScheduler->addResyncSample去将硬件VSync样本加入模型。
void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp,
std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
ATRACE_NAME(vsyncPeriod
? ftl::Concat(__func__, ' ', hwcDisplayId, ' ', *vsyncPeriod, "ns").c_str()
: ftl::Concat(__func__, ' ', hwcDisplayId).c_str());
Mutex::Autolock lock(mStateLock);
if (const auto displayIdOpt = getHwComposer().onVsync(hwcDisplayId, timestamp)) {
// 这里会将硬件样本加入到模型中
if (mScheduler->addResyncSample(*displayIdOpt, timestamp, vsyncPeriod)) {
// period flushed
mScheduler->modulateVsync(displayIdOpt, &VsyncModulator::onRefreshRateChangeCompleted);
}
}
}
5.18 VsyncSchedule::addResyncSample
Scheduler->addResyncSample会调用到VsyncSchedule::addResyncSample
这里会将硬件样本点加入模型,如果样本点足够,就会通知HWC禁用硬件VSync,否则就会重新走一轮请求硬件VSync的流程。
mController->addHwVsyncTimestamp逻辑比较简单,有了前面的基础想必大家猜都可以猜到里面做了什么,感兴趣的话就自己去看一下源码吧,这里就不介绍了。
bool VsyncSchedule::addResyncSample(ISchedulerCallback& callback, TimePoint timestamp,
ftl::Optional<Period> hwcVsyncPeriod) {
bool needsHwVsync = false;
bool periodFlushed = false;
{
std::lock_guard<std::mutex> lock(mHwVsyncLock);
// 会将硬件VSync样本添加到模型中,然后会根据当前样本个数是否足够返回是否需要更多样本。
if (mHwVsyncState == HwVsyncState::Enabled) {
needsHwVsync = mController->addHwVsyncTimestamp(timestamp.ns(),
hwcVsyncPeriod.transform(&Period::ns),
&periodFlushed);
}
}
// 如果还需要,调用enableHardwareVsync请求下一个硬件VSync,5.5节介绍过了这个方法,相当于再重新走请求硬件VSync流程。
if (needsHwVsync) {
enableHardwareVsync(callback);
} else {
disableHardwareVsync(callback, false /* disallow */);
}
return periodFlushed;
}
总结
我们这节详细的讲述来三件事:
- app请求VSync信号并且获得回调的流程
- SurfaceFlinger获取VSync信号,并且获得回调的流程
- 软件模拟的VSync是怎么校准的,如果请求硬件VSync并且得到回调。
相信看完这篇文章大家对VSync有了比较深刻的了解,后面我们就要开始介绍SurfaceFlinger合成相关的逻辑了。