填充完成之后,调用Surface unlockAndPost进行刷图送显。
Surface::unlockAndPost的实现
cpp
status_t Surface::unlockAndPost()
{
status_t err = mLockedBuffer->unlockAsync(&fd);
err = queueBuffer(mLockedBuffer.get(), fd);
mPostedBuffer = mLockedBuffer;
mLockedBuffer = nullptr;
return err;
}
调用了queueBuffer的方法
cpp
int Surface::queueBuffer(sp<GraphicBuffer>&& buffer, int fenceFd,SurfaceQueueBufferOutput* surfaceOutput//默认是nullptr) {
IGraphicBufferProducer::QueueBufferOutput output;
IGraphicBufferProducer::QueueBufferInput input;
........
getQueueBufferInputLocked(buffer, fenceFd, mTimestamp, &input);
sp<Fence> fence = input.fence;
........
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
onBufferQueuedLocked(i, fence, output);
return err;
}
调用了mGraphicBufferProducer生成者的入队列方法
cpp
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
BufferItem item;
item.mAcquireCalled = mSlots[slot].mAcquireCalled;
item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
item.mCrop = crop;
... ...
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener;
if (frameAvailableListener != nullptr) {
frameAvailableListener->onFrameAvailable(item);
} else if (frameReplacedListener != nullptr) {
frameReplacedListener->onFrameReplaced(item);
}
}
重点是调用frameAvailableListener->onFrameAvailable(item);通知Listener当前有可用的buffer了。
cpp
android::BufferQueueConsumer::acquireBuffer BufferQueueConsumer.cpp:85
android::ConsumerBase::acquireBufferLocked ConsumerBase.cpp:392
android::BufferItemConsumer::acquireBuffer BufferItemConsumer.cpp:66
//在这个方法的里面获取bufferItem之后,会进行事务的提交
//status_t status = t->setApplyToken(mApplyToken).apply(false, true)
android::BLASTBufferQueue::acquireNextBufferLocked BLASTBufferQueue.cpp:474
android::BLASTBufferQueue::onFrameAvailable BLASTBufferQueue.cpp:694
android::ConsumerBase::onFrameAvailable ConsumerBase.cpp:157
android::BufferQueue::ProxyConsumerListener::onFrameAvailable BufferQueue.cpp:71
android::BufferQueueProducer::queueBuffer BufferQueueProducer.cpp:1054
android::Surface::queueBuffer Surface.cpp:1190
事务提交之后,会经过binder的调用,调用到surfaceflinger的::setTransactionFlags函数
cpp
void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,FrameHint frameHint,
std::vector<gui::EarlyWakeupInfo> earlyWakeupInfos) {
mScheduler->modulateVsync({}, &VsyncModulator::setTransactionSchedule, schedule,
std::move(earlyWakeupInfos));
uint32_t transactionFlags = mTransactionFlags.fetch_or(mask);
SFTRACE_INT("mTransactionFlags", transactionFlags);
if (const bool scheduled = transactionFlags & mask; !scheduled) {
if (FlagManager::getInstance().resync_on_tx() && FlagManager::getInstance().vsync_predictor_predicts_within_threshold()) {
mScheduler->resync(IEventThreadCallback::ResyncCaller::Transaction);
}
scheduleCommit(frameHint);
} else if (frameHint == FrameHint::kActive) {
// Even if the next frame is already scheduled, we should reset the idle timer
// as a new activity just happened.
mScheduler->resetAllIdleTimers();
}
}
scheduleCommit(frameHint)这个函数会触发任务的执行
cpp
void SurfaceFlinger::scheduleCommit(FrameHint hint, Duration workDurationSlack) {
if (hint == FrameHint::kActive) {
mScheduler->resetAllIdleTimers();
}
mPowerAdvisor->notifyDisplayUpdateImminentAndCpuReset();
mScheduler->scheduleFrame(workDurationSlack);
}
注意 MessageQueue::scheduleFrame
Scheduler继承自MessageQueue,所以这里实际执行的是MessageQueue::scheduleFrame
mVsync.registration->schedule是不是看着很眼熟,2.3.1已经讲过这个逻辑了,最终他会回调VSyncCallbackRegistration内部的mCallback,我们往下来看看这里的mCallback是哪里传入的
cpp
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()});
}
最终回调方法是MessageQueue::vsyncCallback,也可以直接跳到3.5章节。
sf的vsync也是由app层面进行queuebuffer后,通过夸进程setTransactionState方法调用到SurfaceFlinger端,SurfaceFlinger端会检测transation是否有相关的变化,有变化则触发申请vsync信号。
VSyncCallbackRegistration.schedule,这里是请求VSync信号的关键,实际上调用了mDispatch->schedule,这个mDispatch是从VsyncSchedule::createDispatch方法构造的,是一个VSyncDispatchTimerQueue对象,所以这里就是调用VSyncDispatchTimerQueue::schedule。
cpp
//下面是VSyncCallbackRegistration的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)) {
// 。。。
}
上面的调用关系都很简单,没啥业务,直到调用到了dispatch的schedule才是核心
cpp
ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, ScheduleTiming scheduleTiming) {
ScheduleResult result;
{
//这里又会调用到callback的schedule,其实就另一个重载方法,这里会获取出具体的wakeupTime等,是核心部分
result = callback->schedule(scheduleTiming, mTracker, now);
//这里会判断上面计算的wakeupTime是否小于mIntendedWakeupTime,小于才需要重新定时,如果大于就不需要了,直接return
if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
rearmTimerSkippingUpdateFor(now, it);//启动定时任务相关
}
}
return result;
}
来看看核心方法callback->schedule是怎么计算的这个wakeup等重要参数的:
cpp
ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
VSyncTracker& tracker, nsecs_t now) {
//核心方法,给一个时间点,然后可以获取到这个时间点对于的硬件vsync,即上屏的vsync时间点就是nextVsyncTime
auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
//通过nextVsyncTime来获取唤醒时间部分
auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
//省略
//上面计算出来的时间,然后包装到mArmedInfo中
mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
//返回时间点
return getExpectedCallbackTime(nextVsyncTime, timing);
}
//其实是返回wakeuptime
nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime,
const VSyncDispatch::ScheduleTiming& timing) {
return nextVsyncTime - timing.readyDuration - timing.workDuration;
}
核心方法是nextAnticipatedVSyncTimeFrom,这个方法很复杂,大家先把他当做个功能黑盒,后面会带大家详细分析。
https://blog.csdn.net/weixin_43833152/article/details/139940649
2.3.4 VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor
重置定时器,wakeupTime是schedule计算出来的时间,PendingWorkloadUpdate是之前存储的唤醒时间,如果都没有则说明这个callback当前没有人请求VSync,否则就会调用update重新计算这个callback对应的下次VSync唤醒的时间,但是入参callback因为我们刚刚计算过,所以不需要要调用update重新计算。轮询callback找到一个最早的时间来做为定时器需要设置的时间,然后调用setTimer重置定时器。
cpp
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方法。
c
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来确认是否需要配置下一个计时器。
c
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一一关联的。
c
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
c
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信号是怎么产生的。接下去我们看下分发回应用的逻辑。
c
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。
c
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
// 。。。
// 通过BitTube通道发送事件。
auto size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return toStatus(size);
}
发送的app的详细的内容请看上一篇内容android 图形学之 Vsync信号通知产生图层(六)
3.4 MessageQueue::onNewVsyncScheduleLocked
这里的链路实际是在Scheduler初始化时,调用initVsync->onNewVsyncSchedule->onNewVsyncScheduleLocked,但是我们不关注这些,直接来看传入mCallback的地方MessageQueue::onNewVsyncScheduleLocked。
可以看到最终回调方法是MessageQueue::vsyncCallback
c
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
c
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处理消息的地方。
c
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
c
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。
c
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();
}
通过trace加深理解 Begin
所以Sf接收到跨进程transaction的请求后申请vsync,计算出来的vsync时间,从而得出wakeupTime,一般这里的wakeupTime会大于前面app
Vsync时候定时的wakeupTime,所以这里不会进行任何的定时。
结合trace看看vsync的情况:
sf的vsync申请触发部分情况:
app vsync一起合作的解释部分:

这里展开一下app ,sf都被回调的trace,对应的代码就是上面的timeCallback方法:

4、app vsync结束部分
vsync有申请就肯定有结束,不可能app没有申请情况下,vsync还一直不断的运行,这样对于系统的功耗影响巨大,而且也是无用功,所以vsync坚持的原则就是有需要用时候app主动申请,不需要了就停止。
上面只分析了vsync怎么开始的,接下来分析vsync的结束部分逻辑

逻辑是如下情况:
时间到了timeCallback
-----》在onVsyncCallback里面会唤醒EventThread
-------》EventThread运行,但是因为没有app进行requestVsync了,所以vsyncRequest = 0
-----》EventThread继续执行时候发现没有vsyncRequest,故需要调用setVsyncEnbale(false)关闭定时
关闭定时器步骤trace:

该部分对应核心代码回顾:
app的EventThread执行时候,会把vsyncRequest变成0,代表没有app的vsync请求了
cpp
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
DisplayEventConsumers consumers;
while (mState != State::Quit) {
std::optional<DisplayEventReceiver::Event> event;
ATRACE_FORMAT("threadMain");
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,有vsync那么就为true,没有就是false
vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
//注意这里会对每个connection的vsyncRequest进行改变,注意这里的需要event不为null
if (event && shouldConsumeEvent(*event, connection)) {
consumers.push_back(connection);
}
++it;
} else {
it = mDisplayEventConnections.erase(it);
}
}
}
//这个方法里面会改变每个connection的vsyncRequest
bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
const sp<EventThreadConnection>& connection) const {
switch (event.header.type) {
case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
return connection->mEventRegistration.test(
ISurfaceComposer::EventRegistration::modeChanged);
}
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
switch (connection->vsyncRequest) {
case VSyncRequest::None:
return false;
//第一次SingleSuppressCallback后,就改成None
case VSyncRequest::SingleSuppressCallback:
connection->vsyncRequest = VSyncRequest::None;
return false;
case VSyncRequest::Single: {
if (throttleVsync()) {
return false;
}
//第一次Single后,就改成SingleSuppressCallback
connection->vsyncRequest = VSyncRequest::SingleSuppressCallback;
return true;
}
case VSyncRequest::Periodic:
if (throttleVsync()) {
return false;
}
return true;
default:
return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
}
}
}
通过trace加深理解 End
详细的链接看这里:https://h89.cn/archives/293.html