Android4.4深入淺出之SurfaceFlinger總體結構

來源:互聯網
上載者:User

Android4.4深入淺出之SurfaceFlinger總體結構

Android4.4 GUI系統架構之SurfaceFlinger

一. Android GUI架構:

SurfaceFlinger:每當使用者程式重新整理UI的時候,會中介BufferQueue申請一個buffer(dequeueBuffer),然後把UI的資訊填入,丟給SurfaceFlinger,SurfaceFlinger通過計算多重計算合成visibleRegion之後,丟給openGL層處理,處理之後送到顯示器display上顯示。

根據整個Android系統的GUI設計理念,我們不難猜想到至少需要兩種本地視窗:

? 面向管理者(SurfaceFlinger)

既然SurfaceFlinger扮演了系統中所有UI介面的管理者,那麼它無可厚非地需要直接或間接地持有“本地視窗”,這個視窗就是FramebufferNativeWindow

? 面嚮應用程式

這類視窗是Surface(這裡和以前版本出入比較大,之前的版本本地視窗是SurfaceTextureClient)

第二種視窗是能直接顯示在終端螢幕上的——它使用了框架緩衝區,而第一種Window實際上是從記憶體緩衝區分配的空間。當系統中存在多個應用程式時,這能保證它們都可以獲得一個“本地視窗”,並且這些視窗最終也能顯示到螢幕上——SurfaceFlinger會收集所有程式的顯示需求,對它們做統一的映像混合操作。

二. SurfaceFlinger和BufferQueue

一個UI完全顯示到diplay的過程,SurfaceFlinger扮演著重要的角色但是它的職責是“Flinger”,即把系統中所有應用程式的最終的“繪圖結果”進行“混合”,然後統一顯示到物理螢幕上,而其他方面比如各個程式的繪畫過程,就由其他東西來擔任了。這個光榮的任務自然而然地落在了BufferQueue的肩膀上,它是每個應用程式“一對一”的輔導老師,指導著UI程式的“畫板申請”、“作畫流程”等一系列細節。下面的圖描述了這三者的關係:

雖說是三者的關係,但是他們所屬的層卻只有兩個,app屬於java層,BufferQueue/SurfaceFlinger屬於native層。也就是說BufferQueue也是隸屬SurfaceFlinger,所有工作圍繞SurfaceFlinger展開。

這裡IGraphicBufferProducer就是app和BufferQueue重要橋樑,GraphicBufferProducer承擔著單個應用進程中的UI顯示需求,與BufferQueue打交道的就是它。它的工作流程如下:

BpGraphicBufferProducer是GraphicBufferProducer在用戶端這邊的代理對象,負責和SF互動,GraphicBufferProducer通過gbp(IGraphicBufferProducer類對象)向BufferQueue擷取buffer,然後進行填充UI資訊,當填充完畢會通知SF,SF知道後就對該Buffer進行下一步操作。典型的生產-消費者模式。

接下來具體說明用戶端(producer)和服務端SurfaceFlinger(consumer)工作的模式:

首先這裡的buffer是共用緩衝區,故肯定會涉及到互斥鎖,所以buffer的狀態也會有多種,一般的buffer大致會經過FREE->DEQUEUED->QUEUED->ACQUIRED->FREE這個流程,如右圖:

? BufferQueue

可以認為BufferQueue是一個服務中心,其它兩個owner必須要通過它來管理buffer。比如說當producer想要擷取一個buffer時,它不能越過BufferQueue直接與consumer進行聯絡,反之亦然。

? Producer

生產者就是“填充”buffer空間的人,通常情況下當然就是應用程式。因為應用程式不斷地重新整理UI,從而將產生的顯示資料來源源不斷地寫到buffer中。當Producer需要使用一塊buffer時,它首先會向中介BufferQueue發起dequeue申請,然後才能對指定的緩衝區進行操作。這種情況下buffer就屬於producer一個人的了,它可以對buffer進行任何必要的操作,而其它owner此刻絕不能擅自插手。

當生產者認為一塊buffer已經寫入完成後,它進一步調用BufferQueue的queue。從字面上看這個函數是“入列”的意思,形象地表達了buffer此時的操作——把buffer歸還到BufferQueue的隊列中。一旦queue成功後,owner也就隨之改變為BufferQueue了

? Consumer

消費者是與生產者相對應的,它的操作同樣受到BufferQueue的管控。當一塊buffer已經就緒後,Consumer就可以開始工作了。這裡需要特別留意的是,從各個對象所扮演的角色來看,BufferQueue是中介機構,屬於服務提供者;Producer屬於buffer內容的產出方,它對緩衝區的操作是一個“主動”的過程;反之,Consumer對buffer的處理則是“被動”的、“等待式”的——它必須要等到一塊buffer填充完成後才能做工作。在這樣的模型下,我們怎麼保證Consumer可以及時的處理buffer呢?換句話說,當一塊buffer資料ready後,應該怎麼告知Consumer來操作呢?

仔細觀察的話,可以看到BufferQueue裡還同時提供了一個特別的類,名稱為ProxyConsumerListener,其中的函數介面包括:

classProxyConsumerListener : public BnConsumerListener {public:      //省略建構函式        virtual void onFrameAvailable();/*當一塊buffer可以被消費時,這個函數會被調用,特別注意此時沒有共用鎖定的保護*/        virtual voidonBuffersReleased();/*BufferQueue通知consumer它已經釋放其slot中的一個或多個 GraphicBuffer引用*/    private:   wpmConsumerListener;}


這樣子就很清楚了,當有一幀資料準備就緒後,BufferQueue就會調用onFrameAvailable()來通知Consumer進行消費。

BufferQueue和SurfaceFlinger之間的通訊模式如下:

也是有一對BpGraphicBufferConsumer/BnGraphicBufferConsumer支援他們之間的資訊傳輸。

三. 具體分析BufferQueue

首先說明一下BufferQueue的類別關係:

下面是BufferQueue中的核心函數分析:

核心成員函數

說明

setBufferCount

setBufferCount updates the number of available buffer slots.

requestBuffer

requestBuffer returns the GraphicBuffer for slot N.

dequeueBuffer

dequeueBuffer gets the next buffer slot index for the producer to use.

queueBuffer

queueBuffer returns a filled buffer to the BufferQueue.

cancelBuffer

cancelBuffer returns a dequeued buffer to the BufferQueue

acquireBuffer

acquireBuffer attempts to acquire ownership of the next pending buffer BufferQueue.

releaseBuffer

releaseBuffer releases a buffer slot from the consumer back to the BufferQueue.

BufferQueue是IGraphicBufferProducer和IGraphicBufferConsumer的具體實現,使用者在請求和SurfaceFlinger串連的過程中會請求SF建立一個Layer,IGraphicBufferProducer就是在這個過程中擷取一個BufferQueue對象,又轉化成IGraphicBufferProducer類對象,是為了進一步和BufferQueue進行互動,下面是關鍵代碼:

status_t SurfaceFlinger::createNormalLayer(constsp& client,        const String8& name, uint32_t w,uint32_t h, uint32_t flags, PixelFormat& format,        sp* handle, sp*gbpsp* outLayer){    switch (format) {    case PIXEL_FORMAT_TRANSPARENT:    case PIXEL_FORMAT_TRANSLUCENT:        format = PIXEL_FORMAT_RGBA_8888;        break;    case PIXEL_FORMAT_OPAQUE:    } #ifdefNO_RGBX_8888    if (format == PIXEL_FORMAT_RGBX_8888)        format = PIXEL_FORMAT_RGBA_8888;#endif     *outLayer = new Layer(this, client, name,w, h, flags);    status_t err =(*outLayer)->setBuffers(w, h, format, flags);    if (err == NO_ERROR) {        *handle = (*outLayer)->getHandle();        *gbp =(*outLayer)->getBufferQueue();    }     ALOGE_IF(err, "createNormalLayer()failed (%s)", strerror(-err));    return err;}


下面是getBufferQueue的實現,很簡單,擷取BufferQueue對象:

spLayer::getBufferQueue() const {    return mBufferQueue;}


IGraphicBufferProducer是個介面類,它的實現必然在子類BpGraphicBufferProducer中實現,我們來看下這個類:

classBpGraphicBufferProducer : public BpInterface{public:    BpGraphicBufferProducer(constsp& impl)        :BpInterface(impl)    {    }    virtual status_t requestBuffer(intbufferIdx, sp* buf) {        Parcel data, reply;       data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());        data.writeInt32(bufferIdx);        status_t result =remote()->transact(REQUEST_BUFFER, data,&reply);        if (result != NO_ERROR) {            return result;        }        bool nonNull = reply.readInt32();        if (nonNull) {            *buf = new GraphicBuffer();            reply.read(**buf);        }        result = reply.readInt32();        return result;    }    virtual status_t dequeueBuffer(int*buf, sp* fence, bool async,            uint32_t w, uint32_t h, uint32_tformat, uint32_t usage) {        Parcel data, reply;       data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());        data.writeInt32(async);        data.writeInt32(w);        data.writeInt32(h);        data.writeInt32(format);        data.writeInt32(usage);        status_t result = remote()->transact(DEQUEUE_BUFFER, data,&reply);        if (result != NO_ERROR) {            return result;        }        *buf = reply.readInt32();        bool nonNull = reply.readInt32();       if (nonNull) {            *fence = new Fence();            reply.read(**fence);        }        result = reply.readInt32();        return result;    }     virtual status_t queueBuffer(intbuf,            const QueueBufferInput& input,QueueBufferOutput* output) {        Parcel data, reply;       data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());        data.writeInt32(buf);        data.write(input);        status_t result = remote()->transactQUEUE_BUFFER, data, &reply);        if (result != NO_ERROR) {            return result;        }        memcpy(output,reply.readInplace(sizeof(*output)), sizeof(*output));        result = reply.readInt32();        return result;

省去了一些成員函數,只貼出關鍵成員函數,首先這裡的dequeueBuffer和queueBuffer並非真正對Buffer進行操作,留意紅色部分,會發現他只是發出一個“訊息”通知接收方要去

Dequeue一個Buffer或queue一個Buffer。相對應的BnGraphicBufferProducer來接收訊息。

BnGraphicBufferProducer中的onTransact負責這件事:

status_tBnGraphicBufferProducer::onTransact(    uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags){    switch(code) { case DEQUEUE_BUFFER: {           CHECK_INTERFACE(IGraphicBufferProducer, data, reply);            bool async      = data.readInt32();            uint32_t w      = data.readInt32();            uint32_t h      =data.readInt32();            uint32_t format = data.readInt32();            uint32_t usage  = data.readInt32();            int buf;            sp fence;            int result = dequeueBuffer(&buf, &fence, async, w, h,format, usage);            reply->writeInt32(buf);            reply->writeInt32(fence !=NULL);            if (fence != NULL) {                reply->write(*fence);            }            reply->writeInt32(result);            return NO_ERROR;        } break;        case QUEUE_BUFFER: {           CHECK_INTERFACE(IGraphicBufferProducer, data, reply);            int buf = data.readInt32();            QueueBufferInput input(data);            QueueBufferOutput* const output =                    reinterpret_cast(                           reply->writeInplace(sizeof(QueueBufferOutput)));            status_t result = queueBuffer(buf, input, output);            reply->writeInt32(result);            return NO_ERROR;        } break;                 }    return BBinder::onTransact(code, data,reply, flags);}

省略了一些分支,留意紅色部分才發現這裡調用了dequeueBuffer和queueBuffer,

它們的實現在BufferQueue中,這裡才真正踏足到BufferQueue領域中。到這裡用戶端和BufferQueue建立聯絡,接下去的事就是BufferQueue內部處理的事了,BufferQueue和SuefaceFlinger之間的關係也如此。

四. SurfaceFlinger處理buffer

這裡先用2張圖來介紹下SurfaceFlinger的整個訊息處理機制和工作流程:

更具體的代碼流程之前有經過分析。

這裡繼續下去對handleMessageRefresh分析,這是SuefaceFlinger的核心處理函數。

voidSurfaceFlinger::handleMessageRefresh() {    ATRACE_CALL();    preComposition();    rebuildLayerStacks();    setUpHWComposer();    doDebugFlashRegions();    doComposition();postComposition(); //………省略}

preComposition();預先準備“合成物“就是用戶端那邊傳來的UI資訊的buffer;

rebuildLayerStacks();在每一個screen上重建可見地區;

setUpHWComposer();初始化一個硬體容器;

doDebugFlashRegions();這個函數一般進去就返回來了;

doComposition();實質的合成過程,並且合成完的BUFFER由opengl es處理,處理之後由postFramebuffer()送到display上顯示;

這裡重點研究doComposition()

voidSurfaceFlinger::doComposition() {    ATRACE_CALL();    const bool repaintEverything =android_atomic_and(0, &mRepaintEverything);    for (size_t dpy=0 ; dpy&hw(mDisplays[dpy]);        if (hw->canDraw()) {            // transform the dirty region intothis screen's coordinate space            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));             // repaint the framebuffer (ifneeded)            doDisplayComposition(hw, dirtyRegion);            hw->dirtyRegion.clear();            hw->flip(hw->swapRegion);           hw->swapRegion.clear();        }        // inform the h/w that we're donecompositing      hw->compositionComplete();    }    postFramebuffer();}

doDisplayComposition(hw, dirtyRegion);負責渲染的核心函數它的走向是:

doDisplayComposition-> doComposeSurfaces->draw->onDraw->drawWithOpenGL.一直走到OPENGL層。Opengl貼完圖之後,調用了flip函數,在這裡跟之前版本有很大出入,之前版本flip是在postFramebuffer中的,而且函數內容也做了很大的改變,只是計數加一。

在這裡說明一下,UI顯示是雙緩衝機制,每當畫完一個buffer需要flip一下,也就是交換。但在這個版本已經融合到postFramebuffer中:

貼出關鍵代碼

r = hwc.commit();

成員變數hwc是在DisplayHardware::init中產生的一個HWComposer對象。只要HWC_HARDWARE_MODULE_ID模組可以正常載入,且hwc_open能開啟hwc_composer_device裝置,那麼initCheck()就返回NO_ERROR,否則就是NO_INIT。

此時我們通過HWComposer::commit來執行flip,這個函數直接調用如下硬體介面:

mHwc->set(mHwc, mNumDisplays, mLists);

set()和後面的eglSwapBuffers是基本等價的,原型如下:

int (*set)(struct hwc_composer_device*dev,hwc_display_t dpy,

hwc_layer_list_t* list);

其中最後一個list必須與最近一次的prepare()所用列表完全一致。假如list為空白或者列表數量為0的話,說明SurfaceFlinger已經利用OpenGL ES做了composition,此時set就和eglSwapBuffers一樣。當list不為空白,且layer的compositionType == HWC_OVERLAY,那麼HWComposer需要進行硬體合成。

如果成功執行的話,set返回0,否則就是HWC_EGL_ERROR。

如果沒成功的話,後面還有一句:

if (r)

{

hw->hwcSwapBuffers();

}

作用也是跟flip一樣。它的函數走向是:

hwcSwapBuffers->eglSwapBuffers->swapBuffers->advanceFrame-> fbPost->post。

一旦交換完畢就順著這個走向拋給底層display去顯示。

這裡我們主要研究swapBuffers這個函數:

EGLBooleanegl_window_surface_v2_t::swapBuffers(){    //………….    nativeWindow->queueBuffer(nativeWindow,buffer, -1);     // dequeue a new buffer    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd)== NO_ERROR) {        sp fence(new Fence(fenceFd));        if(fence->wait(Fence::TIMEOUT_NEVER)) {           nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);            return setError(EGL_BAD_ALLOC,EGL_FALSE);        }//。。。。。。}


這和我一開始的那張圖的流程是一致的——通過queueBuffer來入隊,然後通過dequeueBuffer重新申請一個buffer以用於下一輪的重新整理。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.