SurfaceFliger与Vsync信号如何建立链接?
链接 如何 建立 信号
2023-06-13 09:13:51 时间
theme: fancy
Vsync信号上报流程
Vsync的注册函数,来临时会回调HWComposer的hook_VSYNC方法,接着调用到vsync方法中
大致流程梳理:
该方法会通知给SurfaceFliger的onVsyncReceived方法,接着调用DispSync的addResyncSample方法。
DispSyncThread线程被唤醒 ,接着EventThread线程唤醒,上面代码中会遍历singalConnections集合调用Connection的postEvent方法
void HWComposer::vsync(int disp, int64_t timestamp) {
if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
{
Mutex::Autolock _l(mLock);
if (timestamp == mLastHwVSync[disp]) {
return; //忽略重复的VSYNC信号
}
mLastHwVSync[disp] = timestamp;
}
//此处mEventHandler是指SurfaceFlinger对象。
mEventHandler.onVSyncReceived(disp, timestamp);
}
}
void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
bool needsHwVsync = false;
{
Mutex::Autolock _l(mHWVsyncLock);
if (type == 0 && mPrimaryHWVsyncEnabled) {
// 此处mPrimaryDispSync为DispSync类
needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
}
}
if (needsHwVsync) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
}
由于上面卡到了DispSync类调用addResyncSample方法处,故先来看这个类。
DispSyncThread线程
DisSync类会创建一个DispSyncThread并运行其run方法
DispSync的初始化过程:
- 运行DispSyncThread线程,用于收集等待Vsync信号的对象并回调这些对象的onDispSyncEvent方法
- 这些等待的对象其实就是DispSyncSource对象 , 是在创建两个EventThread接收的参数
- DispSyncSource的onDispSyncEvent方法阻塞于mCond(Condition)的wait等待被唤醒。
virtual bool threadLoop() {
status_t err;
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
nsecs_t nextEventTime = 0;
while (true) {
Vector<CallbackInvocation> callbackInvocations;
nsecs_t targetTime = 0;
{ // Scope for lock
Mutex::Autolock lock(mMutex);
if (mStop) {
return false;
}
if (mPeriod == 0) {
//在此处阻塞等待
//稍后被DispSync类的addResyncSample方法唤醒
err = mCond.wait(mMutex);
continue;
}
nextEventTime = computeNextEventTimeLocked(now);
targetTime = nextEventTime;
bool isWakeup = false;
if (now < targetTime) {
err = mCond.waitRelative(mMutex, targetTime - now);
if (err == TIMED_OUT) {
isWakeup = true;
} else if (err != NO_ERROR) {
return false;
}
}
now = systemTime(SYSTEM_TIME_MONOTONIC);
if (isWakeup) {
mWakeupLatency = ((mWakeupLatency * 63) +
(now - targetTime)) / 64;
if (mWakeupLatency > 500000) {
mWakeupLatency = 500000;
}
}
//收集vsync信号的所有回调方法
callbackInvocations = gatherCallbackInvocationsLocked(now);
}
if (callbackInvocations.size() > 0) {
//回调所有对象的onDispSyncEvent方法
//这些对象其实就是DispSyncSource
//下面分析
fireCallbackInvocations(callbackInvocations);
}
}
return false;
}
接着分析addResyncSample方法
DispSync::addResyncSample
//最后会调用到updateModelLocked方法
void DispSync::updateModelLocked() {
...
//
mThread->updateModel(mPeriod, mPhase);
}
class DispSyncThread: public Thread {
void updateModel(nsecs_t period, nsecs_t phase) {
Mutex::Autolock lock(mMutex);
mPeriod = period;
mPhase = phase;
//唤醒目标线程就是上面的那个DispSyncThread线程的Condition
mCond.signal();
}
}
fireCallbackInvocations
调用DispSyncSource的onDisPSyncEvent方法
void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
for (size_t i = 0; i < callbacks.size(); i++) {
//此处的Callback就是DispSyncSuorce对象
callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
}
}
//DispSyncSource::onDispSyncEvent
virtual void onDispSyncEvent(nsecs_t when) {
sp<VSyncSource::Callback> callback;
{
Mutex::Autolock lock(mCallbackMutex);
callback = mCallback;
}
if (callback != NULL) {
//调用EventThread的onVSyncEvent方法,该方法会唤醒EventThread线程
//回顾上面ET线程阻塞之后的操作调用Connection的postEvent方法
callback->onVSyncEvent(when);
}
}
此时进入到EventThread线程中
Connection::postEvent
像Bittube发送消息,Looper监听到后发送消息切换到SurfaceFlinger主线程去处理
status_t EventThread::Connection::postEvent(
const DisplayEventReceiver::Event& event) {
//调用DES的sendEvents方法
ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,
Event const* events, size_t count)
{
//通过BitTube发送消息
//init过程中初始化了EventThread后添加到MQ中时就监听了这个BitTube,因此
//会调用到MQ.cb_eventReceiver
return BitTube::sendObjects(dataChannel, events, count);
}
,MQ::cb_eventReceiver
init初始化过程中MQ会监听BitTube,从而调用到cb_eventReceiver方法
大致流程:
发送消息(REFRESH消息),接着就是图形渲染的过程了。
发送消息代码:
int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
return queue->eventReceiver(fd, events);
}
int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
ssize_t n;
DisplayEventReceiver::Event buffer[8];
while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
for (int i=0 ; i<n ; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
#if INVALIDATE_ON_VSYNC
mHandler->dispatchInvalidate();
#else
//分发Refresh消息
mHandler->dispatchRefresh();
#endif
break;
}
}
}
return 1;
}
void MessageQueue::Handler::dispatchRefresh() {
if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
//发送Refresh消息,则进入handleMessage过程
mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
}
}
//MQ中接收到进行处理消息
void MessageQueue::Handler::handleMessage(const Message& message) {
switch (message.what) {
case INVALIDATE:
android_atomic_and(~eventMaskInvalidate, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
case REFRESH:
//回调SurfaceFliger的onMessageReceived方法
android_atomic_and(~eventMaskRefresh, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
case TRANSACTION:
android_atomic_and(~eventMaskTransaction, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
}
}
SurfaceFlinger处理消息
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::TRANSACTION: {
handleMessageTransaction();
break;
}
case MessageQueue::INVALIDATE: {
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded) {
signalRefresh();
}
break;
}
case MessageQueue::REFRESH: {
//该方法处理渲染流程
handleMessageRefresh();
break;
}
}
}
//处理渲染流程
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
preComposition();
rebuildLayerStacks();
setUpHWComposer();
doDebugFlashRegions();
doComposition();
postComposition();
}
流程梳理
- HWComposer接受Vsync信号,
- 唤醒DispSyncThread线程(用于接受Vsync信号),
- 唤醒EventThread线程,调用到DisplayEventReceiver的sendEvent方法再通过BitTube来发送数据
- EventThread创建好后会调用MQ的setEventThread方法监听Bittube,调用MQ的方法因此回调到SurfaceFlinger的主线程中处理
- 进入到渲染流程下篇文章分析
相关文章
- 数据透视表上线!如何在纯前端实现这个强大的数据分析功能?
- lxparse:解析列表页链接和详情页内容
- 如何制作网页链接自动录入工具
- 【星球精选】如何高效构建 Roam 与 theBrain 间细粒度双向链接?
- 织梦php调用底部,dede底部出现织梦官方版权链接”Power by DedeCms”
- 腾讯分阶段实施,字节明确时间表!解除链接屏蔽,大厂回应有玄机!
- php-获得网页的所有链接
- MySQL连接URL:必要技能!(链接mysql的url)
- MySQL全链接:实现传统与云端数据库的超轻松连接(mysql全链接)
- 库修炼Linux:如何修改链接库(linux修改链接)
- 链接错误:如何解决如何处理mysql 10060链接错误?这篇文章提供了一些解决方法,包括检查防火墙、IP地址、端口等等,帮助你重新建立连接。(mysql10060)
- 使用 MySQL 外部链接:轻松实现数据库之间数据共享(mysql外部链接)
- MySQL如何连接远程数据库(mysql链接远程数据库)
- Linux文件链接技术指南(linux 文件 链接)
- Oracle环境下关闭长时链接的方法(oracle 关闭长连接)
- C如何关闭MySQL数据库的链接(c# 关闭mysql链接)
- 如何在MySQL中设置两个表的内部链接(mysql两表设置内链)
- Asp如何与MySQL建立连接(asp能链接mysql吗)
- 初学C语言,如何快速连接Oracle数据库(c 怎么链接oracle)
- MySQL内联接如何优化表连接和查询效率(mysql中内链接)
- 解决如何断开Redis的连接(断开redis链接指令)
- MySQL持续连接如何优化和解决问题(mysql 一直正在链接)
- MySQL如何实现两张表的链接(mysql两张表链接)
- 如何远程访问Redis服务器(如何远程链接redis)
- 如何查看Redis链接数的简单方法(如何查redis链接数)
- 如何增加Referer功能--反向链接插件