app Vsync 的请求、定时、回调和结束

一、app 请求Vsync

app vsync关键的类是EventThread.cpp,在其构造函数里面会开启一个线程在threadMain()函数里面进行循环。当app进程通过binder跨进程请求vsync信号的时候会调EventThread::requestNextVsync()函数。

1、app vsync 的请求

void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
    std::lock_guard<std::mutex> lock(mMutex);
	。。。。。
    if (connection->vsyncRequest == VSyncRequest::None) {
        connection->vsyncRequest = VSyncRequest::Single;
        mCondition.notify_all();
    } 
    。。。。。
}

这里会将connection->vsyncRequest设置为 VSyncRequest::Single,并唤醒threadMain里面的等待。
VSyncRequest分为三中类型,分别为
在这里插入图片描述
None:表示不在进行vsync的定时。
Single:app有vsync请求的时候是这个状态,接下来需要想app返回两次vsync信号。
SingleSuppressCallback:返回一次vsync之后就是这个状态。

接下来我们看一下 threadMain 函数里面:

void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
    DisplayEventConsumers consumers;

    while (mState != State::Quit) {
        std::optional<DisplayEventReceiver::Event> event;
       。。。。。。
        bool vsyncRequested = false;

        // Find connections that should consume this event.
        auto it = mDisplayEventConnections.begin();
        //对所有的connection进行遍历
        while (it != mDisplayEventConnections.end()) {
            if (const auto connection = it->promote()) {
            	//因为前面 request 的时候赋值为 Single, 所以为 true
                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
				。。。。。。
            }
            。。。。。。
        }
		。。。。。。
        State nextState;
        if (mVSyncState && vsyncRequested) {
        	//将	nextState  设置为  State::VSync
            nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
        }
		。。。。。。
        if (mState != nextState) {
            if (mState == State::VSync) {
                mVSyncSource->setVSyncEnabled(false);
            } else if (nextState == State::VSync) {
            // 1、这里开始计算等待时间、并进行定时
                mVSyncSource->setVSyncEnabled(true);
            }
            mState = nextState;
        }
        。。。。。。
    }
}

因为前面将 nextState 设置为 State::VSync,而且 mState 初始化不为 State::VSync,所以会执行到 1 的位置开始进行vsync等待时间,并进行定时。

2、计算 app vsync 的等待时长和定时

void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
		// 这个参数决定了是否停止定时
        mStarted = true;
        mWorkDuration = workDuration;
        mReadyDuration = readyDuration;
		//计算并定时
        auto const scheduleResult =
                mRegistration.schedule({.workDuration = mWorkDuration.count(),
                                        .readyDuration = mReadyDuration.count(),
                                        .earliestVsync = mLastCallTime.count()});
    }

这里将mStarted赋值为true表示开始循环定时,当停止定时就会将mStarted设置为false。
mRegistration.schedule最终会调用到VSyncDispatchTimerQueue::schedule(),在sf vsync文章里面我们说到了VSyncDispatchTimerQueue主要是负责vsync的定时和回调事件。

ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
                                                 ScheduleTiming scheduleTiming) {
    ScheduleResult result;
    {
        std::lock_guard lock(mMutex);

        auto it = mCallbacks.find(token);
        if (it == mCallbacks.end()) {
            return result;
        }
        auto& callback = it->second;
        auto const now = mTimeKeeper->now();

        /* If the timer thread will run soon, we'll apply this work update via the callback
         * timer recalculation to avoid cancelling a callback that is about to fire. */
        auto const rearmImminent = now > mIntendedWakeupTime;
        if (CC_UNLIKELY(rearmImminent)) {
            callback->addPendingWorkloadUpdate(scheduleTiming);
            return getExpectedCallbackTime(mTracker, now, scheduleTiming);
        }
		//1、计算出定时时长
        result = callback->schedule(scheduleTiming, mTracker, now);
        if (!result.has_value()) {
            return result;
        }
// mIntendedWakeupTime 默认是无穷大, 所以这里肯定会通过
        if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
        //2、真正开始定时
            rearmTimerSkippingUpdateFor(now, it);
        }
    }

    return result;
}

(1)计算定时时长

VSyncDispatchTimerQueue.cpp

ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
                                                      VSyncTracker& tracker, nsecs_t now) {
     //通过 VsyncTracker 计算出下一次软件Vsync的时间,在sf vsync 文章中我们讲到VsyncTracker是负责通过 hwVsync 计算出软件vsync的模型                                                
    auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
            std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
    // 计算出下次唤醒的时间
    auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;

    //将计算出的唤醒时间放到 mArmedInfo 
    mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
    return getExpectedCallbackTime(nextVsyncTime, timing);
}

这里的 VSyncDispatchTimerQueueEntry 就是 VSyncDispatchTimerQueue 里面的 mCallbacks (这是一个map)的 value 的类型,map的可以是Token。VSyncDispatchTimerQueueEntry 和app进程的Connection是一一对应的,里面记录了WakeupTime 和 VSyncDispatch::Callback(在定时到的时候会用到)。

关于软件vsync模型的计算我们后面在介绍。

(2)进行定时

void Timer::alarmAt(std::function<void()> callback, nsecs_t time) {
    std::lock_guard lock(mMutex);
	。。。。。。
    if (timerfd_settime(mTimerFd, TFD_TIMER_ABSTIME, &new_timer, &old_timer)) {
        ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);
    }
}

这里就是通过mTimerFd来进行定时的,当时间到了,监听了mTimerFd的就会被唤醒。我们来看一下具体在哪监听的:

bool Timer::dispatch() {
    。。。。。。
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mTimerFd, &timerEvent) == -1) {
        ALOGE("Error adding timer fd to epoll dispatch loop");
        return true;
    }
	。。。。。。
    while (true) {
        。。。。。。
        int nfds = epoll_wait(mEpollFd, events, DispatchType::MAX_DISPATCH_TYPE, -1);
        
		。。。。。

        for (auto i = 0; i < nfds; i++) {
            if (events[i].data.u32 == DispatchType::TIMER) {
                。。。。。
                {
                    cb = mCallback;
                }
                if (cb) {
                    setDebugState(DebugState::InCallback);
                    //执行
                    cb();
                    setDebugState(DebugState::Running);
                }
            }
            。。。。。。
        }
    }
}

从代码我们可以看出是通过epoll来监听mTimerFd的变化,当定时时间到就会往下执行,然后执行cb(),也就是mCallback进行回调。

二、事件的回调

接下来我们看一下事件的回调流程具体是怎么样的。
mCallback是在Timer::alarmAt()函数被调用的时候传递过来的,那么它具体是什么呢?
在这里插入图片描述
所以执行mCallBack就是执行VSyncDispatchTimerQueue::timerCallback 函数:

void VSyncDispatchTimerQueue::timerCallback() {
    struct Invocation {
        std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
        nsecs_t vsyncTimestamp;
        nsecs_t wakeupTimestamp;
        nsecs_t deadlineTimestamp;
    };
    。。。。。。
    for (auto const& invocation : invocations) {
    //这里执行的是 VSyncDispatchTimerQueueEntry 的 callback 函数
        invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
                                      invocation.deadlineTimestamp);
    }
}

我们追寻溯源看一下 VSyncDispatchTimerQueueEntry 的 callback 具体是在哪被赋值的。

VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
        Callback callback, std::string callbackName) {
    std::lock_guard lock(mMutex);
    return CallbackToken{
            mCallbacks
                    .emplace(++mCallbackToken,
                             std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
                                                                            std::move(callback),
                                                                            mMinVsyncDistance))
                    .first->first};
}

那么registerCallback又是在哪调用的呢。

VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
                                                     VSyncDispatch::Callback callback,
                                                     std::string callbackName)
      : mDispatch(dispatch),
        mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))),
        mValidToken(true) {}

是在VSyncCallbackRegistration构造函数里面调用了registerCallback。我们接着往下寻找:
在这里插入图片描述
从这我们知道了 VSyncDispatchTimerQueueEntry 的 callback是CallbackRepeater::callback函数,我们看一下这个函数:

void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
        。。。。。。
        // 1
        mCallback(vsyncTime, wakeupTime, readyTime);

        {
            std::lock_guard lock(mMutex);
            // 2
            if (!mStarted) {
                return;
            }
            // 3
            auto const scheduleResult =
                    mRegistration.schedule({.workDuration = mWorkDuration.count(),
                                            .readyDuration = mReadyDuration.count(),
                                            .earliestVsync = vsyncTime});
            LOG_ALWAYS_FATAL_IF(!scheduleResult.has_value(), "Error rescheduling callback");
        }
    }

我们可以看到又执行了mCallback(vsyncTime, wakeupTime, readyTime),而且 2 处有一个判断使用了 mStarted, 如果mStarted为false则不会继续下一次的定时,这样就停止了 vsync 的申请。反之则会在注释 3处继续调用mRegistration.schedule进行下一次的定时。

从前面我们可以知道 mCallback 是在 CallbackRepeater 创建的时候传过来的,我们找一下:

mCallbackRepeater =
            std::make_unique<CallbackRepeater>(vSyncDispatch,
                                               std::bind(&DispSyncSource::onVsyncCallback, this,
                                                         std::placeholders::_1,
                                                         std::placeholders::_2,
                                                         std::placeholders::_3),
                                               name, workDuration, readyDuration,
                                               std::chrono::steady_clock::now().time_since_epoch());

所有CallbackRepeater 的 mCallback 是 DispSyncSource::onVsyncCallback:

void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
                                     nsecs_t readyTime) {
    VSyncSource::Callback* callback;
    {
        std::lock_guard lock(mCallbackMutex);
        callback = mCallback;
    }
	。。。。。。
    if (callback != nullptr) {
        callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});
    }
}

会执行到callback->onVSyncEvent函数, 因为 EventThread 继承了 VSyncSource::Callback, 所以我们知道最后执行的是EventThread::onVSyncEvent

void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {
   。。。。。。
    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
                                       vsyncData.expectedPresentationTime,
                                       vsyncData.deadlineTimestamp));
    mCondition.notify_all();
}

EventThread::onVSyncEvent就是往mPendingEvents添加一个Event,然后进行线程唤醒,那么我们接下来回到 EventThread 的 threadMain 函数:

void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
    DisplayEventConsumers consumers;

    while (mState != State::Quit) {
        std::optional<DisplayEventReceiver::Event> event;

        // Determine next event to dispatch.
        // onVSyncEvent 函数里添加了 Event,所以mPendingEvents有元素
        if (!mPendingEvents.empty()) {
        // 获取到event,并将这个event从mPendingEvents里面移除
            event = mPendingEvents.front();
            mPendingEvents.pop_front();
            。。。。。。
        }

        bool vsyncRequested = false;

        // Find connections that should consume this event.
        auto it = mDisplayEventConnections.begin();
        while (it != mDisplayEventConnections.end()) {
            if (const auto connection = it->promote()) {
            //connection->vsyncRequest 还是 Single
                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
				// shouldConsumeEvent 判断 connection->vsyncRequest 的值,并将其置为下一阶段
                if (event && shouldConsumeEvent(*event, connection)) {
                // 将请求了 vsync 的connection 放到 consumers
                    consumers.push_back(connection);
                }

                ++it;
            } else {
                it = mDisplayEventConnections.erase(it);
            }
        }
		
		// 前面已经往consumers添加了需要vsync信号的connection,所以不为空
        if (!consumers.empty()) {
        	// 2、开始事件派发
            dispatchEvent(*event, consumers);
            consumers.clear();
        }

        State nextState;
        if (mVSyncState && vsyncRequested) {
            nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
        } else {
            ......
        }
		
		// mState 和 nextState 都是 State::VSync
        if (mState != nextState) {
           ......
        }
		
		// 因为 event 不为空所以继续下一次循环
        if (event) {
            continue;
        }
        if (mState == State::Idle) {
            mCondition.wait(lock);
        } else {
           。。。。。。
           // 1 
            if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                。。。。。。
            }
        }
    }
}

前面我们说了 nextState 被赋值了 State::VSync, 所以在完成定时之后会接着往下执行 1 处的等待,而 EventThread::onVSyncEvent 里面唤醒的等待就是这个,那么就会接着执行下一个循环。注释 2 处开始往app端派发vsync事件,使用的是本地socket方式进行跨进程通信。

三、app 再次请求 vsync

void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
    。。。。。。
    if (connection->vsyncRequest == VSyncRequest::None) {
        connection->vsyncRequest = VSyncRequest::Single;
        mCondition.notify_all();
    } else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {
        connection->vsyncRequest = VSyncRequest::Single;
    }
}

当app端再次请求vysnc信号时,如果 connection->vsyncRequest == VSyncRequest::SingleSuppressCallback,则只会将connection->vsyncRequest 设置为Single,不用唤醒线程。

四、vsync请求停止

要探寻vsync请求的停止,我们要从 EventThread::threadMain 开始。

// 当定时到了,进行事件派发的时候,如果connection->vsyncRequest == SingleSuppressCallback,
//shouldConsumeEvent函数里面会将 shouldConsumeEvent 设置为 None。

void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
    DisplayEventConsumers consumers;

    while (mState != State::Quit) {
        。。。。。。

        bool vsyncRequested = false;

        // Find connections that should consume this event.
        auto it = mDisplayEventConnections.begin();
        while (it != mDisplayEventConnections.end()) {
            if (const auto connection = it->promote()) {
            	// 3
                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
				// 1
                if (event && shouldConsumeEvent(*event, connection)) {
                    consumers.push_back(connection);
                }

                ++it;
            } else {
                it = mDisplayEventConnections.erase(it);
            }
        }

        if (!consumers.empty()) {
            dispatchEvent(*event, consumers);
            consumers.clear();
        }

        State nextState;
        // 4
        if (mVSyncState && vsyncRequested) {
            nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
        } else {
            nextState = State::Idle;
        }
		
		// 5
        if (mState != nextState) {
            if (mState == State::VSync) {
                mVSyncSource->setVSyncEnabled(false);
            } else if (nextState == State::VSync) {
                mVSyncSource->setVSyncEnabled(true);
            }

            mState = nextState;
        }
		
		// 2
        if (event) {
            continue;
        }

        // Wait for event or client registration/request.
        // 6
        if (mState == State::Idle) {
            mCondition.wait(lock);
        } else {
            ......
        }
    }
}

注释 1 : 当定时到了,进行事件派发的时候,如果connection->vsyncRequest == SingleSuppressCallback,shouldConsumeEvent函数里面会将 shouldConsumeEvent 设置为 None。
注释 2 : 会进行下一个循环。
注释3 :是下一个循环的逻辑,因为connection->vsyncRequest == None,所以vsyncRequested 为赋值为false。
注释 4:vsyncRequested 为 false,所以 nextState = State::Idle。
注释 5:nextState 已经在前面被置为 Idle,但是mState还没有改变依然是State::VSync,所以会执行 mVSyncSource->setVSyncEnabled(false)。
注释 6:mState 在前面被赋值为 idle,线程进行等待。

void stop() {
        std::lock_guard lock(mMutex);
        LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");
        mStarted = false;
        //取消上一次的定时
        mRegistration.cancel();
    }

mVSyncSource->setVSyncEnabled(false)最终会调用到CallbackRepeater->stop(),将重要的参数mStarted 置为false,并且取消掉上一次的定时。
而在CallbackRepeater的callback回调函数里面,通过mStarted来判断是否进行下一次的定时,这时候mStarted为false,所以停止了定时。
DispSyncSource.cpp文件里面。

void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
        。。。。。。
        {
            std::lock_guard lock(mMutex);
            
            if (!mStarted) {
                return;
            }
            。。。。。。
        }
    }
  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 中,VSYNC 是通过硬件中断来触发的。具体来说,Android 设备的硬件会以固定的帧率(通常为 60Hz)发送 VSYNC 信号,这个信号会被传递到系统的 VSYNC 时钟中。Android 系统中有一个名为 SurfaceFlinger 的系统服务,它是 Android 图形系统的重要组成部分,主要负责屏幕的渲染和显示。SurfaceFlinger 会注册一个 VSYNC 时钟回调函数,当 VSYNC 信号到来时,VSYNC 时钟回调函数就会被调用。在 SurfaceFlinger 的 VSYNC 时钟回调函数中,会触发 Choreographer 的回调函数,以便使用 Choreographer 协调应用程序的 UI 绘制和动画。 具体来说,在 SurfaceFlinger 的 VSYNC 时钟回调函数中,会执行下面这段代码: ```java // 利用 Choreographer 处理 VSYNC 事件 final long vsyncTime = now; final long intendedVsync = vsyncTime + mFrameIntervalNanos; final long frameStartTime = System.nanoTime(); mChoreographer.doFrame(frameStartTime, intendedVsync); ``` 其中,mChoreographer 是一个 Choreographer 对象,doFrame() 方法是 Choreographer 的一个回调函数,用于处理 VSYNC 事件。在 doFrame() 方法中,会执行下面这些操作: 1. 执行任务队列中的 CALLBACK_TRAVERSAL 类型的任务。 2. 执行任务队列中的 CALLBACK_COMMIT 类型的任务。 3. 执行 Choreographer 自定义的回调函数(例如 FrameCallback)。 通过这种方式,Android 系统就能够很好地协调应用程序的 UI 绘制和动画,以保证应用程序的帧率稳定性和流畅性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值