免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
GUI系統(tǒng)之SurfaceFlinger(7)應(yīng)用程序的典型繪圖流程
分類: Android專欄 2013-05-21 13:21 2435人閱讀 評論(1) 收藏 舉報(bào)

文章都是通過閱讀源碼分析出來的,還在不斷完善與改進(jìn)中,其中難免有些地方理解得不對,歡迎大家批評指正。
轉(zhuǎn)載請注明:From LXS. http://blog.csdn.net/uiop78uiop78/

GUI系統(tǒng)之SurfaceFlinger章節(jié)目錄:
blog.csdn.net/uiop78uiop78/article/details/8954508




1.1.1 應(yīng)用程序的典型繪圖流程

我們知道,BufferQueue有最多達(dá)32個BufferSlot,這樣設(shè)計(jì)的目的是什么?一個可能的原因就是提高圖形渲染速度。因?yàn)榧偃缰挥袃蓚€buffer,可以想象一下,當(dāng)應(yīng)用程序這個生產(chǎn)者的產(chǎn)出效率大于消費(fèi)者的處理速度時,很快它就會dequeue完所有緩沖區(qū)而處于等待狀態(tài),從而導(dǎo)致不必要的麻煩。當(dāng)然,實(shí)際上32只是最大的容量,具體值是可以設(shè)置的,大家可以結(jié)合后面的ProjectButter小節(jié)來理解一下。

前面小節(jié)我們已經(jīng)學(xué)習(xí)了BufferQueue的內(nèi)部原理,那么應(yīng)用程序又是如何與之配合的呢?

解決這個疑惑的關(guān)鍵就是了解應(yīng)用程序是如何執(zhí)行繪圖流程的,這也是本節(jié)我們敘述的重點(diǎn)。不過大家應(yīng)該有個心里準(zhǔn)備,應(yīng)用程序并不會直接使用BufferQueue。和Android系統(tǒng)中很多其它地方一樣,“層層包裹”在這里同樣是存在的,因而我們要盡量抓住其中的重點(diǎn),并輔以一定的手段,才能更好更快地從諸多錯綜復(fù)雜的類關(guān)系中找出問題的答案。

出于以上原因的考慮,我們選取系統(tǒng)的開機(jī)動畫這一應(yīng)用程序,來分析整個圖形繪制的流程。值得一提的是,這個開機(jī)動畫的實(shí)現(xiàn)符合前面提到的兩個改進(jìn)的圖形系統(tǒng)中的第一個,即應(yīng)用程序與SurfaceFlinger都是使用OpenGL ES來完成UI顯示,不過因?yàn)樗且粋€C++程序,所以不需要上層GLSurfaceView的支持。

當(dāng)一個Android設(shè)備上電后,正常情況下它會先后顯示最多4個不一樣的開機(jī)畫面,分別是:

l  boot-loader

這顯然是第一個出現(xiàn)的畫面。因?yàn)閎oot-loader只是負(fù)責(zé)系統(tǒng)后續(xù)模塊的加載與啟動,而且要求文件體積很小,所以一般我們只讓它顯示一張靜態(tài)的圖片

l  kernel

在進(jìn)入內(nèi)核后,同樣會在物理屏幕上有所顯示。和boot-loader一樣,默認(rèn)情況下它也只是一張靜態(tài)圖片

l  android(2個)

Android是系統(tǒng)啟動的最后一個階段,也是最耗時間的一個。它的開機(jī)畫面既可以是靜態(tài)文字描述、靜態(tài)圖片,也可以是動態(tài)畫面。通常第一個是文字或者靜態(tài)圖片(假如指定路徑下的圖片不存在的話,就顯示文字。關(guān)于這方面的資料很多,大家可以自行查閱,我們這里不作過多敘述),另外一個則是動畫,如下圖所示:


圖 11?14 原生態(tài)Android系統(tǒng)中的開機(jī)動畫

 

這個開機(jī)動畫的實(shí)現(xiàn)類是BootAnimation,它的內(nèi)部就是借助SurfaceFlinger來完成的。另外,因?yàn)樗⒉皇莻鹘y(tǒng)意義上的Java層應(yīng)用程序,這使得我們可以拋離很多上層的牽絆,以最直觀的方式來審視BufferQueue的使用,是分析本節(jié)問題的最佳選擇。

BootAnimation是一個C++程序,其工程源碼路徑是/frameworks/base/cmds/bootanimation。和很多native應(yīng)用一樣,它也是在init腳本中被啟動的,大概來看下這一過程。

service bootanim /system/bin/bootanimation

    class main

    user graphics

    group graphics

    disabled

    oneshot

以上內(nèi)容是從init.rc腳本中摘錄出來的,完整地描述了bootanimation這個程序的啟動屬性。如果大家對其中的內(nèi)容不清楚的話,可以參見本書的系統(tǒng)啟動章節(jié)。

當(dāng)bootanimation被啟動后,它首先會進(jìn)入main函數(shù),即main@Bootanimation_main.cpp,生成一個BootAnimation對象,并開啟線程池(因?yàn)樗枰cSurfaceFlinger等系統(tǒng)服務(wù)進(jìn)行跨進(jìn)程的通信)。在BootAnimation的構(gòu)造函數(shù)中,同時生成一個SurfaceComposerClient:

BootAnimation::BootAnimation() : Thread(false)

{

    mSession = newSurfaceComposerClient();

}

SurfaceComposerClient是每個UI應(yīng)用程序與SurfaceFlinger間的獨(dú)立紐帶,后續(xù)很多操作都是通過它來完成的。不過這個類只是一個封裝,真正起作用的還是其內(nèi)部的ISurfaceComposerClient。更多的分析我們將放在后續(xù)小節(jié)中,這里只要先知道它的功能就可以了。值得一提的是,前面小節(jié)中我們講到了ISurfaceTexture,這里又有一個ISurfaceComposerClient,兩者有什么區(qū)別呢?

簡單來說,ISurfaceTexture是應(yīng)用程序與BufferQueue的傳輸通道,而ISurfaceComposerClient則是它與SurfaceFlinger間的橋梁。這樣子的設(shè)計(jì)是合理的,體現(xiàn)了模塊化的思想——SurfaceFlinger的職責(zé)是“Flinger”,即把系統(tǒng)中所有應(yīng)用程序的最終的“繪圖結(jié)果”進(jìn)行“混合”,然后統(tǒng)一顯示到物理屏幕上。它不應(yīng)該,也沒有辦法分出太多的精力去一一關(guān)注各個應(yīng)用程序的“繪畫過程”。這個光榮的任務(wù)自然而然地落在了BufferQueue的肩膀上,它是每個應(yīng)用程序“一對一”的輔導(dǎo)老師,指導(dǎo)著UI程序的“畫板申請”、“作畫流程”等一系列細(xì)節(jié)。下面的圖描述了這三者的關(guān)系:

 


圖 11?15 應(yīng)用程序、BufferQueue及SurfaceFlinger間的關(guān)系

 

所以BootAnimation在其構(gòu)造函數(shù)中就建立了與SurfaceFlinger的聯(lián)系通道。那么它在什么時候會再去建立與BufferQueue的連接呢?因?yàn)锽ootAnimation繼承自RefBase,當(dāng)main函數(shù)中通過sp指針引用它時,會觸發(fā)如下函數(shù):

void BootAnimation::onFirstRef() {

    status_t err =mSession->linkToComposerDeath(this);//監(jiān)聽死亡事件

    if (err == NO_ERROR) {

        run("BootAnimation", PRIORITY_DISPLAY);//開啟線程

    }

}

當(dāng)一個client與遠(yuǎn)程server端的建立了binder聯(lián)系后,它就可以使用這個server的服務(wù)了,但前提是服務(wù)端正常運(yùn)行——換句話說,假如出現(xiàn)了server異常的情況,client又如何知道呢?這就是linkToComposerDeath要解決的問題,它的第一個參數(shù)指明了接收binder server死亡事件的人,在這個例子中就是BootAnimation自身。這是因?yàn)樗^承了IBinder::DeathRecipient,并實(shí)現(xiàn)了其中的binderDied接口。

如果上一步?jīng)]有出錯的話(err== NO_ERROR),接下來就要啟動一個新線程來承載業(yè)務(wù)了。為什么需要獨(dú)立創(chuàng)建一個新的線程呢?前面main函數(shù)中大家應(yīng)該發(fā)現(xiàn)了BootAnimation啟動了binder線程池,可以想象在只有一個線程的情況下,它是不可能既監(jiān)聽binder請求,又去做開機(jī)動畫的繪制的。所以當(dāng)一個新的線程被run起來后,又觸發(fā)了下列函數(shù)的調(diào)用:

status_t BootAnimation::readyToRun() {…  

   /*第一部分,向server端獲得buffer空間,從而得到EGL需要的本地窗口*/

    sp<SurfaceControl>control = session()->createSurface(0, dinfo.w,dinfo.h, PIXEL_FORMAT_RGB_565);

   SurfaceComposerClient::openGlobalTransaction();

    control->setLayer(0x40000000);

   SurfaceComposerClient::closeGlobalTransaction();

sp<Surface> s = control->getSurface();

 

    /*以下為第二部分,即EGL的使用流程*/

    const EGLint attribs[] = {…//屬性值較多,節(jié)約篇幅,我們省略具體內(nèi)容};

    EGLint w, h, dummy;

    EGLint numConfigs;//總共有多少個config

    EGLConfig config;

    EGLSurface surface;

    EGLContext context;

    EGLDisplay display =eglGetDisplay(EGL_DEFAULT_DISPLAY);//第一步,得到默認(rèn)的物理屏幕

    eglInitialize(display, 0,0);//第二步,初始化

    eglChooseConfig(display,attribs, &config, 1, &numConfigs);//第三步,選取最佳的config

    surface =eglCreateWindowSurface(display, config, s.get(),NULL);//第四步,通過本地窗口創(chuàng)建Surface

    context =eglCreateContext(display, config, NULL, NULL);//第五步,創(chuàng)建context環(huán)境

    …

    if(eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)//第六步,設(shè)置當(dāng)前環(huán)境

        return NO_INIT;

    …

    return NO_ERROR;

}

從這個函數(shù)中不但可以看出應(yīng)用程序是如何使用BufferQueue的,而且還有另外一個重要的學(xué)習(xí)點(diǎn),即Opengl ES與EGL的使用流程。在本書應(yīng)用篇章中我們已經(jīng)給出了EGL的使用實(shí)例,這里則可以做為第二個例子。

函數(shù)首先通過session()->createSurface()來獲取一個SurfaceControl。其中session()得到的是mSession變量,也就是前面構(gòu)造函數(shù)中生成的SurfaceComposerClient對象,所以createSurface()最終就是由SurfaceFlinger來實(shí)現(xiàn)的。只不過SurfaceFlinger中返回的其實(shí)是一個ISurface對象,本地端的SurfaceComposerClient又包裝了一層,變成了SurfaceControl,言下之意就是對ISurface進(jìn)行管理。大家肯定會有疑惑,ISurface從哪冒出來的,做什么的?要回答這點(diǎn)不難,只要看下SurfaceFlinger中最終是傳了個什么對象過來就行:

sp<ISurface> SurfaceFlinger::createSurface(…)

{

                sp<LayerBaseClient>layer;

                sp<ISurface>surfaceHandle;

    //中間省略layer的生成過程

                surfaceHandle =layer->getSurface();

                returnsurfaceHandle;…

我們省略了中間一大段過程,只保留與問題相關(guān)的部分,更詳細(xì)的分析可以參見后面的SurfaceFlinger小節(jié)。從中可以清楚看到,ISurface是通過layer->getSurface()得到的。Layer類在SurfaceFlinger中表示“層”的概念,而ISurface則是客戶端與這個“層”進(jìn)行溝通的通道。通俗地講“層”就代表了一個“畫面”,最終的顯示結(jié)果就是通過對系統(tǒng)中同時存在的所有“畫面”進(jìn)行處理得到的。打個比方來說,就好像是一排人各舉著一張繪畫作品,那么觀察者從最前面往后看時,他首先可以看到的就是第一張畫。而假如第一張畫恰好比第二張小,又或者第一張是透明/半透明的(這并非不可能,比如作者是在玻璃上創(chuàng)作的),那么他才能看到第二張畫,以此類推。。。

這個比喻告訴我們,layer是有層級的,越靠近用戶的那個“層”就越有優(yōu)勢。

明白了這個道理,函數(shù)接下來調(diào)用setLayer就不難理解了。不過參數(shù)中傳入了一個數(shù)值0x40000000,這又是什么意思?其實(shí)這個值就是layer的層級,數(shù)字越大就越靠近用戶,在顯示系統(tǒng)中我們通常稱為z-order。以后在Window Manager Service章節(jié)的分析中還會看到對setLayer的調(diào)用,因?yàn)榇藭r系統(tǒng)中還只有開機(jī)畫面一個應(yīng)用程序,所以我們還不需要擔(dān)心z-order的問題。

設(shè)置完層級后,我們接著control->getSurface()來得到一個Surface對象。相關(guān)的類越來越多了,而且由于命名上的不恰當(dāng),進(jìn)一步加劇了大家理解上的困難。其實(shí)可以來猜測下這個類是做什么的?根據(jù)如下:

l  第二部分中的eglCreateWindowSurface使用了Surface,證明它必然是一個本地窗口

l  前幾個小節(jié)我們介紹的兩種本地窗口,一個是FramebufferNativeWindow,另一個是SurfaceTextureClient,那么看來Surface必然要與其中一個有關(guān)聯(lián)。很顯然的,運(yùn)行于應(yīng)用程序端的本地窗口必然是SurfaceTextureClient,我們可以從Surface的繼承關(guān)系中得到驗(yàn)證:

class Surface : public SurfaceTextureClient

的確是太亂了,我們有必要先來整理下目前已經(jīng)出現(xiàn)的容易混淆的相關(guān)類的關(guān)系。

ISurfaceComposerClient: 應(yīng)用程序與SurfaceFlinger間的通道,在應(yīng)用進(jìn)程中則被封裝在SurfaceComposerClient這個類中。這是一個匿名binder server,由應(yīng)用程序(具體位置在SurfaceComposerClient::onFirstRef中)調(diào)用SurfaceFlinger這個實(shí)名binder的createConnection方法來獲取到,服務(wù)端的實(shí)現(xiàn)是SurfaceFlinger::Client。

ISurface:由應(yīng)用程序調(diào)用ISurfaceComposerClient::createSurface()得到,同時在SurfaceFlinger這一進(jìn)程中將會有一個Layer被創(chuàng)建,代表了一個“畫面”。ISurface就是控制這一畫面的handle。

Surface:從邏輯關(guān)系上看,它是上述ISurface的使用者。從繼承關(guān)系上看,它是一個SurfaceTextureClient,也就是本地窗口。SurfaceTextureClient內(nèi)部持有ISurfaceTexture,即BufferQueue的實(shí)現(xiàn)接口。換個角度來思考,當(dāng)EGL想通過Surface這個native window完成某些功能時,后者實(shí)際上又利用ISurface和ISurfaceTexture來取得遠(yuǎn)程服務(wù)端的對應(yīng)服務(wù),以完成EGL的請求。

回到BootAnimation::readyToRun()中來。因?yàn)楸镜卮翱赟urface已經(jīng)成功創(chuàng)建,接下來就該EGL上場了,具體流程我們在代碼中都加了注釋,這里就不贅述了。

當(dāng)EGL準(zhǔn)備好環(huán)境后,意味著程序可以正常使用opengl ES提供的各種API函數(shù)進(jìn)行繪圖了。這部分實(shí)現(xiàn)就集中在隨后的threadLoop()以及android()/movie()中。因?yàn)椴粚儆诒拘」?jié)的討論范圍,有興趣的讀者可以自行參閱學(xué)習(xí)。

最后來做下小結(jié),一個典型的應(yīng)用程序使用SurfaceFlinger進(jìn)行繪圖的流程如下圖所示:


圖 11?16 應(yīng)用程序通過SurfaceFlinger進(jìn)行繪圖的典型流程

 

上圖是從時序縱向角度總結(jié)出來的流程,我們再從橫向的角度來看下,應(yīng)該就更清楚了。


圖 11?17 橫向角度考查Surface相關(guān)類的關(guān)系

 

可以看到,涉及到的類還是比較多的,而且多數(shù)都涉及到跨進(jìn)程通信。希望大家能熟悉這兩張圖,在后幾個小節(jié)的學(xué)習(xí)中,如果覺得混亂的時候也可以回頭來看下,加深印象。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
[Android5.1]開機(jī)動畫顯示工作流程分析
Android應(yīng)用程序窗口(Activity)的繪圖表面(Surface)的創(chuàng)建過程分析
【Android】Graphics
Android 開關(guān)機(jī)動畫顯示源碼分析
Android Display System --- Surface Flinger
聊聊 Android 的 GUI 系統(tǒng)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服