close
`OpenGL ES`與`EGL``OpenGL`

一般OpenGL被認為是一個API(Application Programming Interface, 應用程序編程接口),包含了一系列可以操作圖形、圖像的函數。然而,OpenGL本身並不是一個API,它僅僅是一個由Khronos組織制定並維護的規範(Specification)。

OpenGL規範嚴格規定了每個函數該如何執行,以及它們的輸出值。至於內部具體每個函數是如何實現的,將由OpenGL庫的開發者自行決定

實際的OpenGL庫的開發者通常是顯卡的生產商

OpenGL ES(OpenGL for Embedded Systems) 是從OpenGL裁剪的定製而來的,去除了一些複雜圖元等許多非絕對必要的特性

OpenGL還是很值得學習的,大家可以參考:LearnOpenGL教程的中文翻譯

`EGL`

我們知道OpenGL ES定義了一個渲染圖形的API,但沒有定義窗口系統。

為了讓OpenGL ES能夠適合各種平台,OpenGL ES需要與一個知道如何通過操作系統創建和訪問窗口的庫結合使用

在Android中的這個庫就是EGL。(沒有什麼問題是不能通過增加一個中間層來解決的,有的話那就再增加一個。。。。。)

整體結構如下(網上盜圖):

image`EGL`的用法

使用EGL繪製的一般步驟如下:

獲取 EGL Display 對象:eglGetDisplay()

初始化與 EGLDisplay 之間的連接:eglInitialize()

獲取 EGLConfig 對象:eglChooseConfig()

創建 EGLContext 實例:eglCreateContext()

創建 EGLSurface 實例:eglCreateWindowSurface()

連接 EGLContext 和 EGLSurface:eglMakeCurrent()

使用 OpenGL ES API 繪製圖形:gl_*()

切換 front buffer 和 back buffer 送顯:eglSwapBuffer()

斷開並釋放與 EGLSurface 關聯的 EGLContext 對象:eglRelease()

刪除 EGLSurface 對象

刪除 EGLContext 對象

終止與 EGLDisplay 之間的連接

`Android`中的封裝

前面的章節我們介紹過,無論開發者使用什麼渲染API,一切內容都會渲染到Surface上

此處的Surface指的是framework/native/libs/gui/Surface.cpp對應的業務邏輯

當SurfaceFlinger以消費者的角色獲取到顯示數據後,會開始進行渲染操作,在過程中也存在一個Surface

定義在framework/native/services/surfaceflinger/RenderEngine/Surface.cpp

這個Surface便是對EGL接口的調用封裝,我們看下這個類的定義:

Surface::Surface(constRenderEngine&engine):mEGLDisplay(engine.getEGLDisplay()),mEGLConfig(engine.getEGLConfig()){...}Surface::~Surface(){setNativeWindow(nullptr);}voidSurface::setNativeWindow(ANativeWindow*window){...if(mWindow){mEGLSurface=eglCreateWindowSurface(mEGLDisplay,mEGLConfig,mWindow,nullptr);}}voidSurface::swapBuffers()const{if(!eglSwapBuffers(mEGLDisplay,mEGLSurface)){...}}EGLintSurface::queryConfig(EGLintattrib)const{EGLintvalue;if(!eglGetConfigAttrib(mEGLDisplay,mEGLConfig,attrib,&value)){value=0;}returnvalue;}EGLintSurface::querySurface(EGLintattrib)const{EGLintvalue;if(!eglQuerySurface(mEGLDisplay,mEGLSurface,attrib,&value)){value=0;}returnvalue;}

接口定義結合上面EGL的知識應該很容易理解,下面我們開始SurfaceFlinger學習吧

`SurfaceFlinger`的啟動過程

從Android 4.4開始SurfaceFlinger服務運行在一個獨立的守護進程中(以前在SystemServer中),這樣系統的圖像繪製性能會得到一定的提升。frameworks/native/services/surfaceflinger/surfaceflinger.rc中關於SurfaceFlinger的定義如下:

servicesurfaceflinger/system/bin/surfaceflingerclasscoreanimationusersystemgroupgraphicsdrmrpcreadproconrestartrestartzygote...

可以看到surfaceflinger放到了core組裡,這個組的服務會在系統初始化時啟動。SurfaceFlinger啟動的入口函數main()代碼如下:

intmain(int,char**){...//啟動Gralloc服務startGraphicsAllocatorService();//設置當前Binder服務可連接最大線程數ProcessState::self()->setThreadPoolMaxThreadCount(4);//通過startThreadPool通知Binder驅動當前線程已準備完成sp<ProcessState>ps(ProcessState::self());ps->startThreadPool();//初始化SurfaceFlingersp<SurfaceFlinger>flinger=newSurfaceFlinger();//調整進程優先級為PRIORITY_URGENT_DISPLAYsetpriority(PRIO_PROCESS,0,PRIORITY_URGENT_DISPLAY);//調整調度策略,將其設置為前台進程//這兩種標誌涉及了內核的完全公平調度算法,感興趣的同學可以百度一下//在這裡的目的是保證SurfaceFlinger的較高優先級,方便快速響應更新圖像的請求set_sched_policy(0,SP_FOREGROUND);...//註冊Service前的初始化部分flinger->init();//註冊SurfaceFlinger服務sp<IServiceManager>sm(defaultServiceManager());sm->addService(String16(SurfaceFlinger::getServiceName()),flinger,false,IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL|IServiceManager::DUMP_FLAG_PROTO);//註冊GpuService服務sp<GpuService>gpuservice=newGpuService();sm->addService(String16(GpuService::SERVICE_NAME),gpuservice,false);//啟動DisplayService服務startDisplayService();//dependencyonSFgettingregisteredabove...//runsurfaceflingerinthisthreadflinger->run();return0;}

main()方法中注釋比較詳細就不細說了,方法總結下來有三點:

初始化GraphicsAllocatorService、DisplayService和GpuService服務

set_sched_policy和sched_setscheduler設置進程優先級

SurfaceFlinger對象的初始化以及init和run方法的調用

SurfaceFlinger的初始化過程設計的模塊比較多,我們先簡單看下類關係圖:

image`SurfaceFlinger`對象初始化

SurfaceFlinger的類定義如下:

classSurfaceFlinger:publicBnSurfaceComposer,publicPriorityDumper,privateIBinder::DeathRecipient,privateHWC2::ComposerCallback{}

BnSurfaceComposer類:類圖中該類實現的是ISurfaceComposer接口,而ISurfaceComposer又是一套定義好的Binder類

`Binder`篇提到過,當出現`Bn*`開頭的類就可以把它看做`Binder服務類`了,所以`SurfaceFlinger`這裡是作為一個`Binder`服務對象

上一篇在`SurfaceSession`初始化時,`SurfaceComposerClient`對象就是通過`ServiceManager`獲取了`SurfaceFlinger`服務

然後通過服務提供的`createConnection()`方法獲取了`ISurfaceComposerClient`對象,也就是上面類圖中提到的`Client`類

HWC2::ComposerCallback類:面向底層硬件狀態的監聽回調接口,包括

`onHotplugReceived`,顯示屏熱插拔事件回調

`onRefreshReceived`,通知刷新的回調

`onVsyncReceived`,`VSYNC`信號接收回調

SurfaceFlinger的構造方法如下:

SurfaceFlinger::SurfaceFlinger():SurfaceFlinger(SkipInitialization){ALOGI("SurfaceFlingerisstarting");//初始化vsync信號相關的offsetvsyncPhaseOffsetNs=getInt64<ISurfaceFlingerConfigs,&ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);sfVsyncPhaseOffsetNs=getInt64<ISurfaceFlingerConfigs,&ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);...//確認主屏幕方向V1_1::DisplayOrientationprimaryDisplayOrientation=getDisplayOrientation<V1_1::ISurfaceFlingerConfigs,&V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(V1_1::DisplayOrientation::ORIENTATION_0);switch(primaryDisplayOrientation){caseV1_1::DisplayOrientation::ORIENTATION_90:mPrimaryDisplayOrientation=DisplayState::eOrientation90;break;...}//初始化主屏幕的DispSync對象,這個對象與vsync信號分發有關係mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework,SurfaceFlinger::dispSyncPresentTimeOffset);...//讀取Prop進行一些基礎屬性的設置//是否啟動HWC虛擬顯示property_get("debug.sf.enable_hwc_vds",value,"0");mUseHwcVirtualDisplays=atoi(value);//是否開啟三級緩衝property_get("ro.sf.disable_triple_buffer",value,"1");mLayerTripleBufferingDisabled=atoi(value);...}

構造方法中主要的動作是mPrimaryDispSync.init()操作,餘下基本都是對一些變量的初始化。mPrimaryDispSync的類型是DispSync,這個對象主要是對VSYNC信號進行調整,然後轉發給app或sf,等下完善。

隨着SurfaceFlinger對象創建後的初次引用,也會調用到對象的onFirstRef()方法:

voidSurfaceFlinger::onFirstRef(){mEventQueue->init(this);}

方法中執行了MessageQueue對象的init()方法,這個MessageQueue是SurfaceFlinger自己定義的消息隊列,MessageQueue相關的知識對整個SurfaceFlinger業務邏輯的理解有着關鍵作用,下面細講

鋪墊內容

了解這部分的內容有助於更好的理解SurfaceFlinger後面的init()和run()方法

消息和事件分發-`MessageQueue`

MessageQueue是SurfaceFlinger中用與消息和事件分發的對象,先看下主要的成員變量:

classMessageQueue{...sp<SurfaceFlinger>mFlinger;//指向SurfaceFlinger對象sp<Looper>mLooper;//實現消息機制的Looper對象android::EventThread*mEventThread;//關聯的EventThread對象sp<IDisplayEventConnection>mEvents;gui::BitTubemEventTube;sp<Handler>mHandler;//消息處理Handler...}

MessageQueue的成員變量中

mLooper是一個指向Looper類的指針,它實現了一套完整的消息處理機制

mEventThread指向一個EventThread對象,主要作用是分發VSYNC信號

前面提到在SurfaceFlinger中會調用MessageQueue對象的init()方法,代碼如下:

voidMessageQueue::init(constsp<SurfaceFlinger>&flinger){mFlinger=flinger;mLooper=newLooper(true);mHandler=newHandler(*this);}

init()方法中

創建了Handler對象。此處的Handler是MessageQueue中定義的一個內部類,定義如下:

classMessageQueuefinal:publicandroid::MessageQueue{classHandler:publicMessageHandler{enum{eventMaskInvalidate=0x1,eventMaskRefresh=0x2,eventMaskTransaction=0x4};MessageQueue&mQueue;int32_tmEventMask;...};}

Handler對象中主要處理三種消息:eventMaskInvalidate、eventMaskRefresh、eventMaskTransaction

創建了Looper對象。關於native層的Looper對象在Android 消息機制中已經介紹過,會通過epoll開啟一個消息監聽,具體可以看這個直達入口

init()完成後,MessageQueue就可以通過waitMessage()來等待消息,代碼如下:

voidMessageQueue::waitMessage(){do{IPCThreadState::self()->flushCommands();int32_tret=mLooper->pollOnce(-1);//嘗試讀取消息,-1表示永遠阻塞switch(ret){caseLooper::POLL_WAKE://poll被喚醒caseLooper::POLL_CALLBACK:continue;caseLooper::POLL_ERROR://poll發送錯誤ALOGE("Looper::POLL_ERROR");continue;caseLooper::POLL_TIMEOUT://poll超時//timeout(shouldnothappen)continue;default://shouldnothappenALOGE("Looper::pollOnce()returnedunknownstatus%d",ret);continue;}}while(true);}

waitMessage()是一個無限循環,它的主要作用是循環調用Looper類的pollOnce()從消息隊列中讀取消息

需要注意的是waitMessage()中並沒有消息的處理過程,而且沒有明顯的消息處理方法的調用,那麼具體的消息處理在哪裡? 消息的處理涉及EventThread類,在MessageQueue中通過setEventThread()方法進行關聯,代碼如下:

voidMessageQueue::setEventThread(android::EventThread*eventThread){if(mEventThread==eventThread){return;}if(mEventTube.getFd()>=0){mLooper->removeFd(mEventTube.getFd());}mEventThread=eventThread;//創建連接mEvents=eventThread->createEventConnection();mEvents->stealReceiveChannel(&mEventTube);//重點是這個方法mLooper->addFd(mEventTube.getFd(),0,Looper::EVENT_INPUT,MessageQueue::cb_eventReceiver,this);}

setEventThread()方法中

先調用了EventThread對象的createEventConnection()方法來創建一個連接

sp<BnDisplayEventConnection>EventThread::createEventConnection()const{//創建Connection對象,同時會調用它的onFirstRef方法returnnewConnection(const_cast<EventThread*>(this));}//Connection的構造方法,初始化BitTubemChannel對象,並設置mEventThreadEventThread::Connection::Connection(EventThread*eventThread):count(-1),mEventThread(eventThread),mChannel(gui::BitTube::DefaultSize){}//Connection對象的onFirstRef方法會將自己添加到EventThread中的mDisplayEventConnections中voidEventThread::Connection::onFirstRef(){//NOTE:mEventThreaddoesn'tholdastrongreferenceonusmEventThread->registerDisplayEventConnection(this);}//將connection對象添加到mDisplayEventConnections監聽集合中status_tEventThread::registerDisplayEventConnection(constsp<EventThread::Connection>&connection){std::lock_guard<std::mutex>lock(mMutex);//添加到mDisplayEventConnections集合中mDisplayEventConnections.add(connection);mCondition.notify_all();returnNO_ERROR;}

createEventConnection()方法返回的是一個IDisplayEventConnection對象mEvents

EventThread是一個線程類,用於分發VSYNC消息,

EventThread內部會維護一個gui::BitTube mChannel用於通信,創建過程如下:

接着通過IDisplayEventConnection對象的stealReceiveChannel()方法

該方法主要是設置mEventTube對象的mReceiveFd,mEventTube的類型是BitTube

BitTube對象中包含一對Fd:mReceiveFd和mSendFd,初始化時會通過socketpair()創建全雙工通信

最後通過Looper類的addFd()方法將mReceiveFd添加到epoll監聽列表中,並且傳入了MessageQueue::cb_eventReceiver作為事件的回調方法

intMessageQueue::cb_eventReceiver(intfd,intevents,void*data){MessageQueue*queue=reinterpret_cast<MessageQueue*>(data);returnqueue->eventReceiver(fd,events);}intMessageQueue::eventReceiver(int/*fd*/,int/*events*/){ssize_tn;DisplayEventReceiver::Eventbuffer[8];while((n=DisplayEventReceiver::getEvents(&mEventTube,buffer,8))>0){for(inti=0;i<n;i++){if(buffer[i].header.type==DisplayEventReceiver::DISPLAY_EVENT_VSYNC){mHandler->dispatchInvalidate();break;}}}return1;}

方法最後會調用mHandler-&gt;dispatchInvalidate();方法,這就會涉及到Handler的處理邏輯

回調方法如下:

我們看下Handler中的處理邏輯:

voidMessageQueue::Handler::handleMessage(constMessage&message){switch(message.what){caseINVALIDATE:android_atomic_and(~eventMaskInvalidate,&mEventMask);mQueue.mFlinger->onMessageReceived(message.what);break;caseREFRESH:android_atomic_and(~eventMaskRefresh,&mEventMask);mQueue.mFlinger->onMessageReceived(message.what);break;}}

調用了SurfaceFlinger的onMessageReceived()方法,這裡才是真正處理消息的地方,後面細講這個方法哈

我們先看下EventThread類

消息和事件分發-`EventThread`

EventThread的繼承關係如下:

classEventThread:publicandroid::EventThread,privateVSyncSource::Callback{}

需要注意的是VSyncSource::Callback類,它提供了一個onVSyncEvent()的回調方法

EventThread的構造方法如下(精簡版):

EventThread::EventThread(...){...//創建線程並開始執行,核心業務通過threadMain()方法來完成mThread=std::thread(&EventThread::threadMain,this);//設置一些線程的名稱和優先級pthread_setname_np(mThread.native_handle(),threadName);...//設置調度策略為SP_FOREGROUNDset_sched_policy(tid,SP_FOREGROUND);}

構造方法中啟動了一個線程,這個線程的執行邏輯在threadMain()方法中:

voidEventThread::threadMain()NO_THREAD_SAFETY_ANALYSIS{std::unique_lock<std::mutex>lock(mMutex);//mKeepRunning只會在析構函數中置為falsewhile(mKeepRunning){DisplayEventReceiver::Eventevent;Vector<sp<EventThread::Connection>>signalConnections;//通過waitForEventLocked()循環等待事件//方法中會通過mCondition對象的wait()方法進行等待signalConnections=waitForEventLocked(&lock,&event);constsize_tcount=signalConnections.size();for(size_ti=0;i<count;i++){constsp<Connection>&conn(signalConnections[i]);//通過postEvent()將事件通知到到MessageQueuestatus_terr=conn->postEvent(event);...}}}

threadMain()方法中的重點是:

waitForEventLocked()方法會循環等待消息(也就是VSYNC信號),並獲取到註冊的Connection對象列表

當接收到信號後,通過Connection對象的postEvent()將數據發送到MessageQueue

此時MessageQueue中的Looper會檢測到數據輸入,然後通知回調MessageQueue的cb_eventReceiver()方法

信號分發過程

前面講過VSYNC信號由HWC產生,為了方便接收,HWComposer提供了一個HW2::ComposerCallback用於監聽消息

定義如下:

classComposerCallback{public:virtualvoidonHotplugReceived(...)=0;virtualvoidonRefreshReceived(...)=0;virtualvoidonVsyncReceived(...)=0;virtual~ComposerCallback()=default;};

從前面類關係圖中可以發現,SurfaceFlinger繼承該類,我們重點關注onVsyncReceived()方法

SurfaceFlinger::onVsyncReceived()方法如下:

voidSurfaceFlinger::onVsyncReceived(...){...boolneedsHwVsync=false;{//ScopeforthelockMutex::Autolock_l(mHWVsyncLock);if(type==DisplayDevice::DISPLAY_PRIMARY&&mPrimaryHWVsyncEnabled){//通過addResyncSample來進一步分發信號needsHwVsync=mPrimaryDispSync.addResyncSample(timestamp);}}...}

onVsyncReceived()方法調用mPrimaryDispSync對象的addResyncSample()方法來進一步分發VSYNC信號

mPrimaryDispSync對象的類型是DispSync,這個類比較簡單,核心是它的成員變量mThread,類型是DispSyncThread

DispSyncThread是一個線程類,在DispSync對象初始化時進行創建,代碼如下:

DispSync::DispSync(constchar*name):mName(name),mRefreshSkipCount(0),mThread(newDispSyncThread(name)){}

前面提到過,在SurfaceFlinger的構造方法中會調用DispSync對象的init()進行DispSyncThread線程的啟動

voidDispSync::init(boolhasSyncFramework,int64_tdispSyncPresentTimeOffset){...mThread->run("DispSync",PRIORITY_URGENT_DISPLAY+PRIORITY_MORE_FAVORABLE);...}

addResyncSample()方法中最重要的是執行了DispSyncThread對象的updateModel()方法:

voidupdateModel(nsecs_tperiod,nsecs_tphase,nsecs_treferenceTime){...//省略和VSYNC信號相關的一些賦值操作//重點是此處通過Conditon.signal()來喚醒DispSyncThread線程mCond.signal();}

DispSyncThread線程的執行函數如下:

virtualboolthreadLoop(){...while(true){Vector<CallbackInvocation>callbackInvocations;nsecs_ttargetTime=0;{//Scopeforlock...if(now<targetTime){if(targetTime==INT64_MAX){err=mCond.wait(mMutex);}else{err=mCond.waitRelative(mMutex,targetTime-now);}...}now=systemTime(SYSTEM_TIME_MONOTONIC);...//取得Callback列表callbackInvocations=gatherCallbackInvocationsLocked(now);}//通過fireCallbackInvocations()調用if(callbackInvocations.size()>0){fireCallbackInvocations(callbackInvocations);}}returnfalse;}

threadLoop()中大部分是比較和計算時間,決定是否要發送信號

如果沒有信號發送,就會在mCond上等待

這也就是updateModel()中需要調用mCond的signal()來喚醒的原因

當確認需要發送信號時,先通過gatherCallbackInvocationsLocked()獲取本次VSYNC信號回調通知的監聽對象

這些監聽對象都是通過addEventListener()方法進行添加

最後,通過fireCallbackInvocations()方法一次調用列表中所有對象的onDispSyncEvent()方法

voidfireCallbackInvocations(constVector<CallbackInvocation>&callbacks){if(kTraceDetailedInfo)ATRACE_CALL();for(size_ti=0;i<callbacks.size();i++){callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);}}

查看CallbackInvocation結構就會發現,回調接口的類型是DispSync::Callback

那麼SurfaceFlinger中哪幾個類實現了DispSync::Callback呢? 聰明的我們會發現,SurfaceFlinger中的DispSyncSource繼承了這個類,而且重點是下面部分的代碼:

classDispSyncSourcefinal:publicVSyncSource,privateDispSync::Callback{public:...voidsetVSyncEnabled(boolenable)override{Mutex::Autolocklock(mVsyncMutex);if(enable){status_terr=mDispSync->addEventListener(mName,mPhaseOffset,static_cast<DispSync::Callback*>(this));...}else{status_terr=mDispSync->removeEventListener(static_cast<DispSync::Callback*>(this));...}mEnabled=enable;}...private:virtualvoidonDispSyncEvent(nsecs_twhen){VSyncSource::Callback*callback;...//省略VSYNC信號處理的一些操作callback=mCallback;if(callback!=nullptr){callback->onVSyncEvent(when);}}...}

可以發現:

在調用DispSyncSource對象的setVSyncEnabled()方法時會註冊DispSync的事件監聽

onDispSyncEvent()方法中最終調用了VSyncSource::Callback對象的onVSyncEvent()方法

VSyncSource::Callback對象又是和誰關聯呢? 還記得前面的EventThread麼!!!EventThread便是繼承了VSyncSource::Callback類,我們看下EventThread中關於onVSyncEvent()方法的實現:

voidEventThread::onVSyncEvent(nsecs_ttimestamp){std::lock_guard<std::mutex>lock(mMutex);mVSyncEvent[0].header.type=DisplayEventReceiver::DISPLAY_EVENT_VSYNC;mVSyncEvent[0].header.id=0;mVSyncEvent[0].header.timestamp=timestamp;mVSyncEvent[0].vsync.count++;mCondition.notify_all();}

前面EventThread部分提到過

threadMain中的waitForEventLocked()會通過mCondition.wait()等待消息,

onVSyncEvent()會通過notify_all()喚醒threadMain處理消息

因此會執行到conn-&gt;postEvent(event);方法

postEvent()方法會通過BitTube對象將數據發送到MessageQueue中

接下來便會觸發執行MessageQueue的cb_eventReceiver()方法

前面MessageQueue章節提到過,cb_eventReceiver()方法最後會調用的是SurfaceFlinger的onMessageReceived()方法,而且消息類型是INVALIDATE。

我們看下方法內容:

voidSurfaceFlinger::onMessageReceived(int32_twhat){switch(what){caseMessageQueue::INVALIDATE:{...boolrefreshNeeded=handleMessageTransaction();...break;}caseMessageQueue::REFRESH:{handleMessageRefresh();break;}}}

INVALIDATE消息的處理邏輯比較複雜,我們重點關注的是handleMessageTransaction()方法,它會創建DisplayDevice對象。我們先看下DisplayDevice對象

顯示設備的抽象-`DisplayDevice`

DisplayDevice類是顯示設備的抽象,當前Android 9中定義了3種顯示設備類型:

DISPLAY_PRIMARY:主顯示設備

DISPLAY_EXTERNAL:擴展顯示設備,通過HDMI輸出的顯示信號

DISPLAY_VIRTUAL:虛擬顯示設備,通過WIFI輸出的顯示信號

這三種顯示設備,第一種是基本配置,另外兩種需要硬件支持。關於Display官網有個極其簡單的介紹:傳送門

在SurfaceFlinger中DisplayDevice負責與OpenGL ES交互,即使沒有任何物理顯示設備被檢測到,SurfaceFlinger都需要一個DisplayDevice對象才能正常工作

SurfaceFlinger將需要顯示的圖層Layer通過DisplayDevice對象傳遞到OpenGL ES中進行合成,合成後再通過HWComposer對象傳送到FrameBuffer中顯示

DisplayDevice對象中的成員變量Vector< sp<Layer> > mVisibleLayersSortedByZ;保存了所有需要在本設備中顯示的Layer對象

DisplayDevice比較複雜,先簡單了解下它的創建流程。前面提到了handleMessageTransaction()方法中會創建DisplayDevice對象,我們看下具體的創建流程:

初步調用流程:handleMessageTransaction()-->handleTransactionLocked()-->processDisplayChangesLocked()

voidSurfaceFlinger::processDisplayChangesLocked(){...if(!curr.isIdenticalTo(draw)){...for(size_ti=0;i<cc;i++){if(draw.indexOfKey(curr.keyAt(i))<0){constDisplayDeviceState&state(curr[i]);sp<DisplaySurface>dispSurface;sp<IGraphicBufferProducer>producer;sp<IGraphicBufferProducer>bqProducer;sp<IGraphicBufferConsumer>bqConsumer;//mCreateBufferQueue是一個函數指針,指向的是BufferQueue::createBufferQueue//這就很熟悉了,和我們前面分析Surface時創建的BufferQueue一樣mCreateBufferQueue(&bqProducer,&bqConsumer,false);int32_thwcId=-1;if(state.isVirtualDisplay()){...//省略虛擬屏幕創建的邏輯}else{...hwcId=state.type;//創建FramebufferSurface用於數據傳輸dispSurface=newFramebufferSurface(*getBE().mHwc,hwcId,bqConsumer);producer=bqProducer;}constwp<IBinder>&display(curr.keyAt(i));if(dispSurface!=nullptr){//通過setupNewDisplayDeviceInternal()創建DisplayDevice對象//並添加到mDisplays集合中mDisplays.add(display,setupNewDisplayDeviceInternal(display,hwcId,state,dispSurface,producer));if(!state.isVirtualDisplay()){mEventThread->onHotplugReceived(state.type,true);}}}}}mDrawingState.displays=mCurrentState.displays;}sp<DisplayDevice>SurfaceFlinger::setupNewDisplayDeviceInternal(constwp<IBinder>&display,inthwcId,constDisplayDeviceState&state,constsp<DisplaySurface>&dispSurface,constsp<IGraphicBufferProducer>&producer){...//mCreateNativeWindowSurface也是一個函數指針,執行的是NativeWindowSurface::create()方法//該方法利用IGraphicBufferProducer生成NativeWindowSurface和NativeWindow對象//其實也是EGL相關的接口調用autonativeWindowSurface=mCreateNativeWindowSurface(producer);autonativeWindow=nativeWindowSurface->getNativeWindow();//通過渲染引擎創建OpenGL渲染的目標EGLSurfacestd::unique_ptr<RE::Surface>renderSurface=getRenderEngine().createSurface();renderSurface->setCritical(state.type==DisplayDevice::DISPLAY_PRIMARY);renderSurface->setAsync(state.type>=DisplayDevice::DISPLAY_VIRTUAL);//執行eglCreateWindowSurface操作renderSurface->setNativeWindow(nativeWindow.get());...//創建DisplayDevice對象sp<DisplayDevice>hw=newDisplayDevice(this,state.type,hwcId,state.isSecure,display,nativeWindow,dispSurface,std::move(renderSurface),displayWidth,displayHeight,hasWideColorGamut,hdrCapabilities,supportedPerFrameMetadata,hwcColorModes,initialPowerMode);...returnhw;}

上面的代碼中通過BufferQueue::createBufferQueue創建了consumer和producer對象(這部分和前面講的BufferQueue的邏輯是相同的)

並基於創建的consumer對象和一個HWComposer對象創建了一個FramebufferSurface對象

最後將上面的對象作為參數通過setupNewDisplayDeviceInternal()方法創建DisplayDevice對象,並添加到mDisplays集合中

DisplayDevice對象創建完成,意味着SurfaceFlinger就可以利用DisplayDevice對象寫入圖像數據,並通過

EGLSurface-->BufferQueue-->FrameBufferSurface-->HWCComposer-->Gralloc

這樣一條路徑到達顯示設備的FrameBuffer中

`SurfaceFlinger`的`init()`和`run()`

有了前面的鋪墊知識,init()和run()就很好理解了

`SurfaceFlinger::init`voidSurfaceFlinger::init(){//創建app的DispSyncSource和EventThreadmEventThreadSource=std::make_unique<DispSyncSource>(&mPrimaryDispSync,SurfaceFlinger::vsyncPhaseOffsetNs,true,"app");mEventThread=std::make_unique<impl::EventThread>(mEventThreadSource.get(),...,"appEventThread");//創建sf的DispSyncSource和EventThreadmSfEventThreadSource=std::make_unique<DispSyncSource>(&mPrimaryDispSync,SurfaceFlinger::sfVsyncPhaseOffsetNs,true,"sf");mSFEventThread=std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),...,"sfEventThread");//將mSFEventThread與MessageQueue進行關聯mEventQueue->setEventThread(mSFEventThread.get());//將mSFEventThread和mEventThread添加到VSYNC信號調製器中mVsyncModulator.setEventThreads(mSFEventThread.get(),mEventThread.get());//創建渲染引擎,主要是選擇EGL配置,選擇OpenGL版本,創建OpenGL上下文getBE().mRenderEngine=RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,...);...//初始化HWCgetBE().mHwc.reset(newHWComposer(std::make_unique<Hwc2::impl::Composer>(getBE().mHwcServiceName)));//註冊HWC的Callback監聽//VSYNC信號便會從這裡進行回調通知getBE().mHwc->registerCallback(this,getBE().mComposerSequenceId);...//創建VSYNC事件接收控制對象,enable=true表示允許HWC產生VSYNC信號//sufacefinlger通過這個對象來控制HWC是否產生VSYNC信號mEventControlThread=std::make_unique<impl::EventControlThread>([this](boolenabled){setVsyncEnabled(HWC_DISPLAY_PRIMARY,enabled);});...//該方法會通過MessageQueue發送一個異步消息//消息處理中會完成primaryDisplayDevice的創建,並進行VSYNC周期的設定initializeDisplays();...//根據PresentFenceIsNotReliable屬性創建StartPropertySetThread對象if(getHwComposer().hasCapability(HWC2::Capability::PresentFenceIsNotReliable)){mStartPropertySetThread=newStartPropertySetThread(false);}else{mStartPropertySetThread=newStartPropertySetThread(true);}//執行StartPropertySetThread,該線程會通過setProp觸發開機動畫,包括設置以下兩個Prop//property_set("service.bootanim.exit","0");復位動畫退出標記//property_set("ctl.start","bootanim");啟動開機動畫if(mStartPropertySetThread->Start()!=NO_ERROR){ALOGE("RunStartPropertySetThreadfailed!");}...ALOGV("Doneinitializing");}

init()方法初始化了很多重要的對象:

初始化app和sf兩組DispSyncSource和EventThread對象

這兩個分別代表了`VSYNC`信號的兩個消費者:`App`和`SurfaceFlinger`

`sf`對應的信號分發邏輯與鋪墊知識中的一致,因為是通過`mEventQueue->setEventThread()`來進行的關聯

`app`的信號分發邏輯等下細看

初始化HWComposer,並通過registerCallback()註冊HWC2::ComposerCallback監聽

初始化EventControlThread對象,SurfaceFlinger用這個對象來控制HWC是否需要產生VSYNC信號

默認設置為不需要產生`VSYNC`信號

初始化StartPropertySetThread線程,該線程會通過setProp的方式觸發開機動畫

`SurfaceFlinger::run`

run()方法比較簡單:

voidSurfaceFlinger::run(){do{waitForEvent();}while(true);}

方法中執行了一個無限循環來調用waitForEvent(),具體代碼如下:

voidSurfaceFlinger::waitForEvent(){mEventQueue->waitMessage();}

waitForEvent()方法又調用了MessageQueue對象的waitMessage()方法進入一個無限循環,這個方法在MessageQueue部分中已經介紹過就不細講啦

所以對於SurfaceFlinger進程來說,執行完run()當前線程就會進入一個無限循環,剩下的業務處理都變成了消息驅動來實現

`App`的繪製通知

在SurfaceFlinger的init()方法中初始化了一個appEventThread,在接收到VSYNC信號後,它便會通知到App去進行繪製操作,我們看下這個通知流程

再看`onResume()`

我們已經知道,onResume()方法後才會進行View的顯示,這部分體現在ActivityThread中的handleResumeActivity()方法中,代碼如下:

publicvoidhandleResumeActivity(...){...//TODOPushresumeArgsintotheactivityforconsiderationfinalActivityClientRecordr=performResumeActivity(token,finalStateRequest,reason);if(r==null){//Wedidn'tactuallyresumetheactivity,soskippinganyfollow-upactions.return;}finalActivitya=r.activity;...if(r.window==null&&!a.mFinished&&willBeVisible){r.window=r.activity.getWindow();Viewdecor=r.window.getDecorView();decor.setVisibility(View.INVISIBLE);ViewManagerwm=a.getWindowManager();WindowManager.LayoutParamsl=r.window.getAttributes();a.mDecor=decor;l.type=WindowManager.LayoutParams.TYPE_BASE_APPLICATION;l.softInputMode|=forwardBit;...if(a.mVisibleFromClient){if(!a.mWindowAdded){a.mWindowAdded=true;wm.addView(decor,l);}else{a.onWindowAttributesChanged(l);}}}...}

上面performResumeActivity()會回調應用程序的onResume()函數。不過本次我們重點關注的是wm.addView()方法,最後調用到的是WindowManagerGlobal.java的addView(),代碼如下:

publicvoidaddView(...){...ViewRootImplroot;ViewpanelParentView=null;synchronized(mLock){...root=newViewRootImpl(view.getContext(),display);view.setLayoutParams(wparams);mViews.add(view);mRoots.add(root);mParams.add(wparams);//dothislastbecauseitfiresoffmessagestostartdoingthingstry{root.setView(view,wparams,panelParentView);}catch(RuntimeExceptione){//BadTokenExceptionorInvalidDisplayException,cleanup.if(index>=0){removeViewLocked(index,true);}throwe;}}}

重點是初始化了ViewRootImpl對象,我們看下ViewRootImpl中的setView()方法的調用:

publicvoidsetView(Viewview,WindowManager.LayoutParamsattrs,ViewpanelParentView){synchronized(this){if(mView==null){mView=view;...requestLayout();...}}}publicvoidrequestLayout(){if(!mHandlingLayoutInLayoutRequest){checkThread();mLayoutRequested=true;scheduleTraversals();}}voidscheduleTraversals(){if(!mTraversalScheduled){mTraversalScheduled=true;mTraversalBarrier=mHandler.getLooper().getQueue().postSyncBarrier();mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,mTraversalRunnable,null);if(!mUnbufferedInputDispatch){scheduleConsumeBatchedInput();}notifyRendererOfFramePending();pokeDrawLockIfNeeded();}}

執行到scheduleTraversals()方法就引出來一個最重要的類Choreographer,整個應用布局的渲染依賴這個對象的發動。

在scheduleTraversals()方法中調用了mChoreographer對象的postCallback()方法添加了一個回調對象mTraversalRunnable

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,mTraversalRunnable,null);

mTraversalRunnable回調對象的定義如下:

finalclassTraversalRunnableimplementsRunnable{@Overridepublicvoidrun(){doTraversal();}}

doTraversal內部會調用大名鼎鼎的performTraversal()方法,到這裡App就可以進行measure/layout/draw三大流程

那麼 mTraversalRunnable對象是在什麼時候調用的呢? 我們帶着疑問,先看下應用是如何接收VSYNC信號的

`Choreographer`類

App要求渲染動畫或者更新畫面布局時都會用到Choreographer,接收VSYNC信號也依賴於Choreographer

在上面的scheduleTraversals()方法中執行了Choreographer對象的postCallback()方法

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,mTraversalRunnable,null);

這個方法的含義就是應用程序請求VSYNC信號,接收到VSYNC信號後執行mTraversalRunnable回調

那麼接下來我們看下Choreographer如何接收vsync信號

`DisplayEventReceiver`類

應用層可以通過DisplayEventReceiver類用來接收vsync信號,當接收到vsync信號後,會執行DisplayEventReceiver對象的onVsync()方法

DisplayEventReceiver是在Android的View體系中定義的一個抽象類,對外隱藏的,核心定義如下

publicabstractclassDisplayEventReceiver{...//用來表示APP的VSYNC信號源publicstaticfinalintVSYNC_SOURCE_APP=0;publicDisplayEventReceiver(Looperlooper){this(looper,VSYNC_SOURCE_APP);}publicDisplayEventReceiver(Looperlooper,intvsyncSource){...mMessageQueue=looper.getQueue();mReceiverPtr=nativeInit(newWeakReference<DisplayEventReceiver>(this),mMessageQueue,vsyncSource);...}privatestaticnativelongnativeInit(WeakReference<DisplayEventReceiver>receiver,MessageQueuemessageQueue,intvsyncSource);privatestaticnativevoidnativeDispose(longreceiverPtr);privatestaticnativevoidnativeScheduleVsync(longreceiverPtr);...publicvoidonVsync(longtimestampNanos,intbuiltInDisplayId,intframe){}...}

需要關注的是

構造方法中調用了native方法nativeInit()來進行初始化操作

定義了一個onVsync()方法的空實現,當接收到VSYNC信號後便會調用該方法

先看下nativeInit()的實現

staticjlongnativeInit(JNIEnv*env,jclassclazz,jobjectreceiverWeak,jobjectmessageQueueObj,jintvsyncSource){sp<MessageQueue>messageQueue=android_os_MessageQueue_getMessageQueue(env,messageQueueObj);...sp<NativeDisplayEventReceiver>receiver=newNativeDisplayEventReceiver(env,receiverWeak,messageQueue,vsyncSource);status_tstatus=receiver->initialize();...}

nativeInit()方法創建了一個NativeDisplayEventReceiver對象,並調用了它的initialize()方法

NativeDisplayEventReceiver繼承了DisplayEventDispatcher類,那麼我們的重點便是DisplayEventDispatcher,頭文件定義如下:

classDisplayEventDispatcher:publicLooperCallback{public:DisplayEventDispatcher(constsp<Looper>&looper,ISurfaceComposer::VsyncSourcevsyncSource=ISurfaceComposer::eVsyncSourceApp);status_tinitialize();...private:sp<Looper>mLooper;DisplayEventReceivermReceiver;...};

核心實現如下:

DisplayEventDispatcher::DisplayEventDispatcher(constsp<Looper>&looper,ISurfaceComposer::VsyncSourcevsyncSource):mLooper(looper),mReceiver(vsyncSource),mWaitingForVsync(false){ALOGV("dispatcher%p~Initializingdisplayeventdispatcher.",this);}status_tDisplayEventDispatcher::initialize(){status_tresult=mReceiver.initCheck();...intrc=mLooper->addFd(mReceiver.getFd(),0,Looper::EVENT_INPUT,this,NULL);if(rc<0){returnUNKNOWN_ERROR;}returnOK;}

在鋪墊知識部分已經了解到,如果應用要接收VSYNC信號,需要將其添加到對應的EventThread中,SF中一共創建了兩個

mSFEventThread是SurfaceFlinger專用的

在`SurfaceFlinger`的`init()`中通過`mEventQueue->setEventThread()`進行關聯

`setEventThread()`在鋪墊部分也介紹過(鋪墊內容-消息和事件分發)

mEventThread用來通知App的

我們知道mEventQueue->setEventThread()關聯VSYNC信號的過程主要分為了兩步:

創建連接

註冊監聽

對比DisplayEventDispatcher中我們會發現

DisplayEventDispatcher的initialize()中做了一個mLooper-&gt;addFd()操作

前面介紹過:Looper類的addFd()方法是將mReceiveFd添加到epoll監聽列表

這樣,註冊監聽的部分我們找到了

DisplayEventDispatcher中包含一個native層的DisplayEventReceiver對象mReceiver

DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSourcevsyncSource){sp<ISurfaceComposer>sf(ComposerService::getComposerService());if(sf!=NULL){//createDisplayEventConnection方法便會調用mEventThread->createEventConnection()來創建連接//而mEventThread便是App的VSYNC分發線程mEventConnection=sf->createDisplayEventConnection(vsyncSource);if(mEventConnection!=NULL){mDataChannel=std::make_unique<gui::BitTube>();mEventConnection->stealReceiveChannel(mDataChannel.get());}}}

native層的DisplayEventReceiver便封裝了創建連接的過程,我們需要關注的是構造方法部分

到這裡,DisplayEventReceiver便和SurfaceFlinger中的mEventThread建立了聯繫,當VSYNC信號產生後,SurfaceFlinger便會通過mEventThread通知到DisplayEventReceiver

VSYNC 分發過程已經介紹過了,可以看這裡

`FrameDisplayEventReceiver`類

DisplayEventReceiver是一個抽象類,FrameDisplayEventReceiver便是這個類的具體實現,在Choreographer中定義,代碼如下:

privatefinalclassFrameDisplayEventReceiverextendsDisplayEventReceiverimplementsRunnable{privatebooleanmHavePendingVsync;privatelongmTimestampNanos;privateintmFrame;publicFrameDisplayEventReceiver(Looperlooper,intvsyncSource){super(looper,vsyncSource);}@OverridepublicvoidonVsync(longtimestampNanos,intbuiltInDisplayId,intframe){//vsync信號分發時便會回調到這裡...mTimestampNanos=timestampNanos;mFrame=frame;Messagemsg=Message.obtain(mHandler,this);msg.setAsynchronous(true);//這裡發了一個消息,此處並未主動設置msg.what,默認值應為0//0對應的數值為MSG_DO_FRAMEmHandler.sendMessageAtTime(msg,timestampNanos/TimeUtils.NANOS_PER_MS);}@Overridepublicvoidrun(){mHavePendingVsync=false;doFrame(mTimestampNanos,mFrame);}}

上面onVsync會往消息隊列放一個消息,通過下面的FrameHandler進行處理:

privatefinalclassFrameHandlerextendsHandler{publicFrameHandler(Looperlooper){super(looper);}@OverridepublicvoidhandleMessage(Messagemsg){switch(msg.what){caseMSG_DO_FRAME:doFrame(System.nanoTime(),0);break;caseMSG_DO_SCHEDULE_VSYNC:doScheduleVsync();break;caseMSG_DO_SCHEDULE_CALLBACK:doScheduleCallback(msg.arg1);break;}}}

對於MSG_DO_FRAME消息,會執行doFrame()方法,關鍵代碼如下:

voiddoFrame(longframeTimeNanos,intframe){...mFrameInfo.markInputHandlingStart();doCallbacks(Choreographer.CALLBACK_INPUT,frameTimeNanos);mFrameInfo.markAnimationsStart();doCallbacks(Choreographer.CALLBACK_ANIMATION,frameTimeNanos);mFrameInfo.markPerformTraversalsStart();doCallbacks(Choreographer.CALLBACK_TRAVERSAL,frameTimeNanos);doCallbacks(Choreographer.CALLBACK_COMMIT,frameTimeNanos);...}

doFrame()方法通過doCallbacks()執行了各種類型的Callback,分為4類:

CALLBACK_INPUT : 處理輸入事件處理有關

CALLBACK_ANIMATION :處理Animation的處理有關

CALLBACK_TRAVERSAL : 處理和UI等控件繪製有關

CALLBACK_COMMIT :處理Commit相關回調

需要注意的是CALLBACK_TRAVERSAL類型的doCallbacks()

doCallbacks(Choreographer.CALLBACK_TRAVERSAL,frameTimeNanos);

這個方法便會執行前面在scheduleTraversals()方法中添加的mTraversalRunnable回調。而由於CALLBACK_INPUT 、CALLBACK_ANIMATION會修改View的屬性,所以要先於CALLBACK_TRAVERSAL執行

結語

狡辯ING:剛接手新平台比較忙,導致本來清明節計劃學習的章節一直拖到現在,好在磕磕絆絆的學習完了

SurfaceFlinger這部分涉及的知識很多,很遺憾深入Android系統(十二)Android圖形顯示系統系列也僅僅只是記錄一些基礎知識。

View的繪製部分也並未展開學習,考慮到後面的章節,等了解完整個Android系統知識後再來補充吧(挖坑ING…..)

原文鏈接: https://juejin.cn/post/6958064165458018317

推薦:

Android 圖形系統概述

Android 圖形顯示系統

全網最全的 Android 音視頻和 OpenGL ES 乾貨,都在這了

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()