快盘下载:好资源、好软件、快快下载吧!

快盘排行|快盘最新

当前位置:首页软件教程电脑软件教程 → SurfaceFliger与Vsync信号如何建立链接?

SurfaceFliger与Vsync信号如何建立链接?

时间:2022-10-10 13:32:56人气:作者:快盘下载我要评论

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的主线程中处理进入到渲染流程下篇文章分析

SurfaceFliger与Vsync信号如何建立链接?

相关文章

网友评论

快盘下载暂未开通留言功能。

关于我们| 广告联络| 联系我们| 网站帮助| 免责声明| 软件发布

Copyright 2019-2029 【快快下载吧】 版权所有 快快下载吧 | 豫ICP备10006759号公安备案:41010502004165

声明: 快快下载吧上的所有软件和资料来源于互联网,仅供学习和研究使用,请测试后自行销毁,如有侵犯你版权的,请来信指出,本站将立即改正。