日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android surfaceflinger研究----SurfaceFlinger loop

發(fā)布時間:2025/3/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android surfaceflinger研究----SurfaceFlinger loop 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?? 上一篇文章介紹了整個Surface機制(我是這么稱呼的,主要是Surface的建立,Surface的顯示存儲的管理),同時我們也介紹過了整個顯示系統(tǒng),那么這篇文章就介紹一下SurfaceFlinger 這個核心服務層的機制。

? ? 從代碼中我們可以看出SurfaceFlinger 是一個thread,運行在system_server進程中,并且其threadLoop()方法的返回值為true,因此它是一個循環(huán)的loop。這樣保證了SurfaceFlinger業(yè)務的循環(huán)周期性。

? ? 首先,先來個綜述,下圖是我總結的一個SurfaceFlinger結構的概括圖:



1. SurfaceFlinger的同步

? ??SurfaceFlinger 并不是時時刻刻都在執(zhí)行業(yè)務中,當WMS請求SurfaceFlinger創(chuàng)建Surface,或者WMS對Surface進行屬性設置時,我們希望此時的SurfaceFlinger并不進行顯示操作,以保證對Surface的線程保護,因此SurfaceFlinger 的loop中實現了同步機制。

[cpp]?view plaincopy
  • waitForEvent();??
  • ??? 主要的同步情況有如下幾種,當然也有其他一些要求SurfaceFlinger同步的情況,不夠對于研究SurfaceFlinger就不太重要了

    ? ? 1. 創(chuàng)建Surface同步

    ? ? 假如當前只有一個Client,比如WMS請求SufaceFlinger創(chuàng)建一個Surface,那么此時應該保持SurfaceFlinger loop處在block狀態(tài),因為這個過程涉及到對一些成員變量的處理,為了保證同步而需要hold住整個loop。

    ? ? 2. 設置Surface屬性或SurfaceFlinger屬性同步

    ? ? 創(chuàng)建完Surface之后,WMS會請求SurfaceFlinger對其Layer進行屬性設置或者對SurfaceFlinger的屬性進行設置,如上面概括圖中SurfaceComposerClient中的函數接口。

    ? ? 3. Surface繪制同步

    ? ? 當ViewRoot對Surface進行繪制時,同樣需要將SurfaceFlinger hold住,當整個窗口繪制完成之后,再向SurfaceFlinger發(fā)送signal信號。如下面時序圖所示。

    ? ??

    ? ? 4. freeze/unfreeze同步

    ? ?當每個Activity啟動的時候,AMS都會請求WMS freeze整個屏幕,當Activity啟動之后,再unfreeze整個屏幕,我猜測這么做的目的是為了保證在Activity以及Activity的窗口在創(chuàng)建過程中,對Activity窗口的Surface進行的線程保護,以免出現屏幕的閃爍等用戶體驗較差的現象。


    2. Layer存儲

    ? ? 在SurfaceFlinger中,Layer是怎么樣存儲的呢?所有的Layer,不論是那個Client創(chuàng)建的Layer,均保存在一個名為layersSortedByZ的變量中,也就是說WMS請求創(chuàng)建的Surface的Layer和其他Client請求創(chuàng)建的Layer都保存在layersSortedByZ中,但是layersSortedByZ保存過程中則遵守一定的規(guī)則。下面代碼中的do_compare揭示了這個規(guī)則。

    @SurfaceFlinger.h

    [cpp]?view plaincopy
  • class?LayerVector?:?public?SortedVector<?sp<LayerBase>?>?{??
  • public:??
  • ????LayerVector()?{?}??
  • ????LayerVector(const?LayerVector&?rhs)?:?SortedVector<?sp<LayerBase>?>(rhs)?{?}??
  • ????virtual?int?do_compare(const?void*?lhs,?const?void*?rhs)?const?{??
  • ????????const?sp<LayerBase>&?l(*reinterpret_cast<const?sp<LayerBase>*>(lhs));??
  • ????????const?sp<LayerBase>&?r(*reinterpret_cast<const?sp<LayerBase>*>(rhs));??
  • ????????//?sort?layers?by?Z?order??
  • ????????uint32_t?lz?=?l->currentState().z;??
  • ????????uint32_t?rz?=?r->currentState().z;??
  • ????????//?then?by?sequence,?so?we?get?a?stable?ordering??
  • ????????return?(lz?!=?rz)???(lz?-?rz)?:?(l->sequence?-?r->sequence);??
  • ????}??
  • };??
  • ? ? 每次向 layersSortedByZ中添加新的Layer,都會做一次排序,按照規(guī)則將其放在合適的位置。

    ? ? 1. 首先,按照Layer的Z-order值來排序,Z-order值小的,放在layersSortedByZ低索引值位置;

    ? ? 2. 其次,如果兩個Layer?Z-order值相同,sequence值小的,放在layersSortedByZ低索引值位置;

    ? ??Z-order值如何確定?

    ? ? WMS根據不同的Window Type來確定Z-order值,Z-order = LAYER*TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET。

    根據下面代碼中的不同的Window Type的LAYER值,可以確定Z-order值,例如TYPE_APPLICATION窗口,其

    Z-order = 2*10000+1000 = 21000。

    ? ? @PhoneWindowManager.java

    [java]?view plaincopy
  • //?wallpaper?is?at?the?bottom,?though?the?window?manager?may?move?it.??
  • ?static?final?int?WALLPAPER_LAYER?=?2;??
  • ?static?final?int?APPLICATION_LAYER?=?2;??
  • ?static?final?int?PHONE_LAYER?=?3;??
  • ?static?final?int?SEARCH_BAR_LAYER?=?4;??
  • ?static?final?int?STATUS_BAR_PANEL_LAYER?=?5;??
  • ?static?final?int?SYSTEM_DIALOG_LAYER?=?6;??
  • ?//?toasts?and?the?plugged-in?battery?thing??
  • ?static?final?int?TOAST_LAYER?=?7;??
  • ?static?final?int?STATUS_BAR_LAYER?=?8;??
  • ?//?SIM?errors?and?unlock.??Not?sure?if?this?really?should?be?in?a?high?layer.??
  • ?static?final?int?PRIORITY_PHONE_LAYER?=?9;??
  • ?//?like?the?ANR?/?app?crashed?dialogs??
  • ?static?final?int?SYSTEM_ALERT_LAYER?=?10;??
  • ?//?system-level?error?dialogs??
  • ?static?final?int?SYSTEM_ERROR_LAYER?=?11;??
  • ?//?on-screen?keyboards?and?other?such?input?method?user?interfaces?go?here.??
  • ?static?final?int?INPUT_METHOD_LAYER?=?12;??
  • ?//?on-screen?keyboards?and?other?such?input?method?user?interfaces?go?here.??
  • ?static?final?int?INPUT_METHOD_DIALOG_LAYER?=?13;??
  • ?//?the?keyguard;?nothing?on?top?of?these?can?take?focus,?since?they?are??
  • ?//?responsible?for?power?management?when?displayed.??
  • ?static?final?int?KEYGUARD_LAYER?=?14;??
  • ?static?final?int?KEYGUARD_DIALOG_LAYER?=?15;??
  • ?//?things?in?here?CAN?NOT?take?focus,?but?are?shown?on?top?of?everything?else.??
  • ?static?final?int?SYSTEM_OVERLAY_LAYER?=?16;??
  • ?static?final?int?SECURE_SYSTEM_OVERLAY_LAYER?=?17;??
  • ? ??

    ? ??sequence值如何確定?

    ? ??sequence值是根據Layer的創(chuàng)建的順序來維護這個序列值,下面代碼中的LayerBase的構造函數中的sequence值,每創(chuàng)建一個Layer,sSequence加一賦值給sequence。

    @LayerBase.cpp

    [cpp]?view plaincopy
  • int32_t?LayerBase::sSequence?=?1;??
  • ??
  • LayerBase::LayerBase(SurfaceFlinger*?flinger,?DisplayID?display)??
  • ????:?dpy(display),?contentDirty(false),??
  • ??????sequence(uint32_t(android_atomic_inc(&sSequence))),??
  • ??????mFlinger(flinger),??
  • ??????mNeedsFiltering(false),??
  • ??????mOrientation(0),??
  • ??????mLeft(0),?mTop(0),??
  • ??????mTransactionFlags(0),??
  • ??????mPremultipliedAlpha(true),?mName("unnamed"),?mDebug(false),??
  • ??????mInvalidate(0)??
  • {??
  • ????const?DisplayHardware&?hw(flinger->graphicPlane(0).displayHardware());??
  • ????mFlags?=?hw.getFlags();??
  • ????mBufferCrop.makeInvalid();??
  • ????mBufferTransform?=?0;??
  • }??

  • 3.?屬性更新

    ? ? 這一節(jié)的所描述的實現都在函數handleTransactionLocked()中。

    ? ? 從上面概括圖中可以看出,WMS可以對SurfaceFlinger進行屬性設置,也可以對當前的Surface對應的Layer進行屬性設置,因此handleTransactionLocked()函數就是對SurfaceFlinger屬性和設置了新屬性的Layer的屬性更新。

    [cpp]?view plaincopy
  • enum?{??
  • ????eTransactionNeeded??????=?0x01,??
  • ????eTraversalNeeded????????=?0x02??
  • };??
  • ? ?? SurfaceFlinger根據這個枚舉值來確定handleTransactionLocked()需要更新SurfaceFlinger屬性還是layer屬性。

    ? ? 如果SurfaceFlinger屬性被設置了新內容,則SurfaceFlinger會記錄標志eTransactionNeeded;如果layer屬性被設置了新內容,那么
    SurfaceFlinger會記錄標志eTraversalNeeded。handleTransactionLocked()通過記錄的標志來執(zhí)行各自的屬性得更新。‘

    ? ? 這里提到的屬性的更新,主要是看SurfaceFlinger或者laye新設置的屬性與舊的屬性相比,哪些屬性做了修改,然后

    記錄下來,在接下來的SurfaceFlinger loop中使用新的屬性來顯示圖形。

    ? ? 類SurfaceFlinger 和Layer中各自定義了兩個屬性的變量,其中mCurrentState為新設置屬性,mDrawingState為顯示圖形時用到的屬性,一般為舊屬性。不過類SurfaceFlinger 和Layer分別定義了不同的State類。

    [cpp]?view plaincopy
  • State???????????????????mCurrentState;??
  • State???????????????????mDrawingState;??
  • 4. 圖形緩存

    ? ? 這一部分的的實現在函數handlePageFlip()中。

    ? ? 有這么一種可能,當前顯示到顯示設備上的layer不止一個,而且layer是按照Z-Order的順序來疊加到OpenGL的surface上的,那么這就需要layer的Z-Order值和坐標來確定每個layer能夠被顯示的區(qū)域。

    4.1 page flip

    ? ? 前面一篇文章中介紹過,每個surface均有2個buffer供使用,一個作為FronteBuffer供SurfaceFlinger去顯示,另外一個作為BackBuffer供ViewRoot去繪制窗口。因此在顯示各個layer之前,我們需要做一個page flip過程,將當前的已經繪制了應用窗口的BackBuffer選擇為FrontBuffer,用于顯示;將之前的已經顯示完成的FrontBuffer在重置為BackBuffer供ViewRoot去繪制。

    ? ?而實現這個page flip的過程很簡單

    lockPageFlip()@Layer.cpp

    [cpp]?view plaincopy
  • ssize_t?buf?=?lcblk->retireAndLock();??
  • SharedBufferServer::RetireUpdate::operator()@SharedBufferStack.cpp

    [cpp]?view plaincopy
  • head?=?(head?+?1)?%?numBuffers;??
  • ? ??


    4.2 紋理初始化

    ? ? 為每個Buffer的紋理進行初始化,為當前的紋理創(chuàng)建一個EGLImageKHR,將當前的Buffer最為該EGLImageKHR的源。這樣OpenGL就可以進行紋理映射。

    lockPageFlip()@Layer.cpp

    [cpp]?view plaincopy
  • /*?a?buffer?was?posted,?so?we?need?to?call?reloadTexture(),?which?
  • ?*?will?update?our?internal?data?structures?(eg:?EGLImageKHR?or?
  • ?*?texture?names).?we?need?to?do?this?even?if?mPostedDirtyRegion?is?
  • ?*?empty?--?it's?orthogonal?to?the?fact?that?a?new?buffer?was?posted,?
  • ?*?for?instance,?a?degenerate?case?could?be?that?the?user?did?an?empty?
  • ?*?update?but?repainted?the?buffer?with?appropriate?content?(after?a?
  • ?*?resize?for?instance).?
  • ?*/??
  • reloadTexture(?mPostedDirtyRegion?);??

  • 4.3 計算顯示區(qū)域

    ? ? 通過layer的疊加,我們可以計算出總的顯示區(qū)域以及每個layer需要顯示的區(qū)域,它的實現在computeVisibleRegions()函數中。這個函數主要計算了layer疊加后的總的顯示區(qū)域,以及每個layer需要顯示的區(qū)域。整個的計算過程比較簡單,只是需要注意不透明區(qū)域的處理,computeVisibleRegions()需要計算出一個不透明區(qū)域,通過這個不透明區(qū)域驗證WMS提供給layer的區(qū)域是否正確。即下面代碼中的mWormholeRegion計算,mWormholeRegion為屏幕區(qū)域減去不透明區(qū)域,正常情況mWormholeRegion應該為空,即不透明區(qū)域范圍應該為屏幕區(qū)域,如果不透明區(qū)域小雨屏幕區(qū)域,那么說明當前的應用程序出現了設置的錯誤。今天有個網友就出現了這個問題。

    handlePageFlip()

    [cpp]?view plaincopy
  • const?Region?screenRegion(hw.bounds());??
  • if?(visibleRegions)?{??
  • ????Region?opaqueRegion;??
  • ????computeVisibleRegions(currentLayers,?mDirtyRegion,?opaqueRegion);??
  • ??
  • ????/*?
  • ?????*??rebuild?the?visible?layer?list?
  • ?????*/??
  • ????mVisibleLayersSortedByZ.clear();??
  • ????const?LayerVector&?currentLayers(mDrawingState.layersSortedByZ);??
  • ????size_t?count?=?currentLayers.size();??
  • ????mVisibleLayersSortedByZ.setCapacity(count);??
  • ????for?(size_t?i=0?;?i<count?;?i++)?{??
  • ????????if?(!currentLayers[i]->visibleRegionScreen.isEmpty())??
  • ????????????mVisibleLayersSortedByZ.add(currentLayers[i]);??
  • ????}??
  • ??
  • ????mWormholeRegion?=?screenRegion.subtract(opaqueRegion);??
  • ????mVisibleRegionsDirty?=?false;??
  • }??
  • ? ? 在computeVisibleRegions()疊加計算總的顯示范圍,layer的計算順序從上到下的過程計算的,也就是先計算Z-Order值較大的,顯示在最上層的layer開始往下計算。這么做的好處就是能夠很好的計算出不透明區(qū)域的范圍。

    ? ? 在SurfaceFlinger的區(qū)域相互之間的操作處理如下:


    ? ??

    ? ??

    ? ??


    ? ??

    4.4 圖形緩存

    ? ? 前面選擇了FrontBuffer、初始化了紋理、計算了layer的顯示區(qū)域,那么下一步就該將Buffer內容進行圖形處理并保存到OpenGL緩存中。

    ? ? 調用每個layer的draw函數來進行這個操作。如下面代碼所示。具體的圖形處理過程很復雜,完全交給OpenGL去處理,這里我們就不去關心了。我們只需要知道最終經過圖形處理的內容會被緩存到OpenGL的緩存區(qū)中。

    [cpp]?view plaincopy
  • void?SurfaceFlinger::composeSurfaces(const?Region&?dirty)??
  • {??
  • ????if?(UNLIKELY(!mWormholeRegion.isEmpty()))?{??
  • ????????//?should?never?happen?unless?the?window?manager?has?a?bug??
  • ????????//?draw?something...??
  • ????????drawWormhole();??
  • ????}??
  • ????const?Vector<?sp<LayerBase>?>&?layers(mVisibleLayersSortedByZ);??
  • ????const?size_t?count?=?layers.size();??
  • ????for?(size_t?i=0?;?i<count?;?++i)?{??
  • ????????const?sp<LayerBase>&?layer(layers[i]);??
  • ????????const?Region?clip(dirty.intersect(layer->visibleRegionScreen));??
  • ????????if?(!clip.isEmpty())?{??
  • ????????????layer->draw(clip);??
  • ????????}??
  • ????}??
  • }??
  • ? ? 從前面的顯示系統(tǒng)中,介紹過,Surface的緩存Buffer就是FramebufferNativeWindow中定義的2個Buffer,如果/dev/fb0讀取設備信息,如果設備支持page flip,那么Surface的緩存Buffer即從/dev/fb0設備中申請;如果不支持,我們則需要從/dev/pmem中申請,同時/dev/fb0還會提供一個Buffer以便圖形最終的顯示。

    ? ??/dev/fb0不支持page flip模式

    ? ??

    ? ??/dev/fb0支持page flip模式

    ? ??

    5. 圖形顯示

    ? ? 當圖形內容被緩存到frameBuffer中后,最后的一步就是圖形顯示。代碼中很明確就是SurfaceFlinger loop中的postFramebuffer()函數了。

    ? ? 這個函數最終回調到OpenGL的eglSwapBuffers()函數,這個函數主要有2個步驟(由于硬件加速代碼不可見,我們仍然以軟件加速為例)

    ? ? 1. 顯示當前緩存buffer中內容;

    ? ? ?首先,將原來的屏幕上的內容與最新需要顯示的內容進行區(qū)域相減,將原來的內容copy到當前的緩存buffer中;

    EGLBoolean egl_window_surface_v2_t::swapBuffers()@frameworks\base\opengl\libagl\egl.cpp

    [cpp]?view plaincopy
  • /*?
  • ?*?Handle?eglSetSwapRectangleANDROID()?
  • ?*?We?copyback?from?the?front?buffer??
  • ?*/??
  • if?(!dirtyRegion.isEmpty())?{??
  • ????dirtyRegion.andSelf(Rect(buffer->width,?buffer->height));??
  • ????if?(previousBuffer)?{??
  • ????????const?Region?copyBack(Region::subtract(oldDirtyRegion,?dirtyRegion));??
  • ????????if?(!copyBack.isEmpty())?{??
  • ????????????void*?prevBits;??
  • ????????????if?(lock(previousBuffer,???
  • ????????????????????GRALLOC_USAGE_SW_READ_OFTEN,?&prevBits)?==?NO_ERROR)?{??
  • ????????????????//?copy?from?previousBuffer?to?buffer??
  • ????????????????copyBlt(buffer,?bits,?previousBuffer,?prevBits,?copyBack);??
  • ????????????????unlock(previousBuffer);??
  • ????????????}??
  • ????????}??
  • ????}??
  • ????oldDirtyRegion?=?dirtyRegion;??
  • }??
  • ? ? 其次,如果當前的緩存buffer是申請自/dev/fb0,那么直接去顯示這個緩存區(qū)中內容;如果 緩存buffer是申請自/dev/pmem,那么需要將緩存buffer中內容拷貝到/dev/fb0 buffer中去,其結構如上一節(jié)所示。

    ? ? 2. 對2個緩存buffer進行page flip(swap)操作。

    ? ? 通過?queueBuffer()操作將將當前Buffer交還給FramebufferNativeWindow,同時調用fb_post進行圖形顯示。然后通過dequeueBuffer()操作獲得另外一個FramebufferNativeWindow的緩存Buffer,實現page flip(swap)操作。


    ?

    ? ? 至此,整個的SurfaceFlinger的機制就分析完了。


    原文地址:?http://blog.csdn.net/windskier/article/details/7060995

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的android surfaceflinger研究----SurfaceFlinger loop的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。