android surfaceflinger研究----显示系统
? 這周抽空研究了一下SurfaceFlinger,發(fā)現(xiàn)真正復(fù)雜的并不是SurfaceFlinger本身,而是Android的display顯示系統(tǒng),網(wǎng)上關(guān)于這部分的介紹有不少,本不打算寫的,但是發(fā)現(xiàn)還是記錄一下研究代碼的過(guò)程比較好,一是能夠幫助自己理清思路,另一個(gè)原因就是以后當(dāng)這塊內(nèi)容忘記的時(shí)候,能快速的通過(guò)這個(gè)記錄撿起來(lái)。
? ? 一. ?android顯示系統(tǒng)的建立
我們看SurfaceFlinger的定義就知道,它其實(shí)是一個(gè)Thread, 因此SurfaceFlinger的初始化工作就理所當(dāng)然的放在了SurfaceFlinger線程中,詳見readyToRun()@SurfaceFlinger.cpp? ??SurfaceFlinger對(duì)于顯示的管理是通過(guò)一個(gè)或多個(gè)GraphicPlane對(duì)象(目前android只實(shí)現(xiàn)了一個(gè))來(lái)管理的,
@SurfaceFlinger.h
[cpp]?view plaincopy
? ? 1. FrameBuffer的建立
? ??framebuffer,確切的是說(shuō)是linux下的framebuffer,,它是linux圖形顯示系統(tǒng)中一個(gè)與圖形硬件無(wú)關(guān)的抽象層,user完全不用考慮我們的硬件設(shè)備,而僅僅使用framebuffer就可以實(shí)現(xiàn)對(duì)屏幕的操作。
? ? android的framebuffer并沒(méi)有被SurfaceFlinger直接使用,而是在framebuffer外做了一層包裝,這個(gè)包裝就是FramebufferNativeWindow,我們來(lái)看一下FramebufferNativeWindow的創(chuàng)建過(guò)程。
? ?我們的framebuffer是由一個(gè)設(shè)備符fbDev來(lái)表示的,它是FramebufferNativeWindow的一個(gè)成員,我們來(lái)分析一下對(duì)fbDev的處理過(guò)程。
? ? 1.1. fbDev設(shè)備符
? ? 1.1.1?gralloc library
? ? 在這之前,先介紹一下gralloc library,它的形態(tài)如grallocBOARDPLATFORM.so,?BOARDPLATFORM可以從屬性ro.board.platform中獲得,這篇文章中我們以Qualcomm?msmx7x30為例,也就是gralloc.msm7x30.so中,它的源路徑在hardware/msm7k/libgralloc-qsd8k。
? ? framebuffer的初始化需要通過(guò)HAL?gralloc.msm7x30.so 來(lái)完成與底層硬件驅(qū)動(dòng)的適配,但是gralloc library并不是平臺(tái)無(wú)關(guān)的,不同的vendor可能會(huì)實(shí)現(xiàn)自己的gralloc library,因此為了保證在創(chuàng)建framebuffer時(shí)能夠平臺(tái)無(wú)關(guān),android只能是動(dòng)態(tài)的判斷并使用當(dāng)前的gralloc library,android通過(guò)從gralloc library中再抽象出一個(gè)hw_module_t結(jié)構(gòu)來(lái)供使用,它為framebuffer的初始化提供了需要的gralloc.msm7x30.so業(yè)務(wù)。因此通過(guò)這個(gè)hw_module_t結(jié)構(gòu)我們就不需要知道當(dāng)前系統(tǒng)使用的到底是哪個(gè)gralloc library。按規(guī)定,所有g(shù)ralloc library中的這個(gè)結(jié)構(gòu)體被命名為HAL_MODULE_INFO_SYM(HMI)。當(dāng)前分析的系統(tǒng)中,HAL_MODULE_INFO_SYM在hardware/msm7k/libgralloc-qsd8k/galloc.cpp。
? ? 1.1.2?打開fbDev設(shè)備符? ??
? ? 下面看如何打開?打開fbDev設(shè)備符。通過(guò)HAL_MODULE_INFO_SYM提供的gralloc.msm7x30.so的接口我們調(diào)用到了fb_device_open()@hardware/msm7k/libgralloc-qsd8kframebuffer.cpp。
[cpp]?view plaincopy
在這個(gè)函數(shù)中,主要為fbDev設(shè)備符指定一個(gè)fb_context_t實(shí)例,并通過(guò)函數(shù)mapFrameBuffer()對(duì)設(shè)備節(jié)點(diǎn)/dev/graphics/fb0進(jìn)行操作,操作的目的有:
1.獲得屏幕設(shè)備的信息,并將屏幕信息保存在HAL_MODULE_INFO_SYM(上面代碼中的module)中。
?2. 向/dev/graphics/fb0請(qǐng)求page flip模式,page flip模式需要至少2個(gè)屏幕大小的buffer,page flip模式在后面介紹。目前android系統(tǒng)中設(shè)置為2個(gè)屏幕大小的buffer。當(dāng)然屏幕設(shè)備可能不支持page flip模式。
mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp
[cpp]?view plaincopy
3. 映射屏幕設(shè)備緩存區(qū)給fbDev設(shè)備符。
mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp
[cpp]?view plaincopy
1.2 grDev設(shè)備符
在為framebuffer,也就是FramebufferNativeWindow申請(qǐng)內(nèi)存之前,我們還要介紹一個(gè)概念,就是grDev設(shè)備符。它雖然也叫設(shè)備符,但是它和具體的設(shè)備沒(méi)有直接關(guān)系,我們看它的類型就是知道了alloc_device_t,沒(méi)錯(cuò),grDev設(shè)備符就是為了FramebufferNativeWindow管理內(nèi)存使用的。為FramebufferNativeWindow提供了申請(qǐng)/釋放內(nèi)存的接口。
? ? 1.3 FramebufferNativeWindow內(nèi)存管理
FramebufferNativeWindow維護(hù)了2個(gè)buffer,? [cpp]?view plaincopy? ? 1.3.1 屏幕設(shè)備支持page filp模式
目前的android系統(tǒng)默認(rèn)要求屏幕設(shè)備給系統(tǒng)映射2個(gè)屏幕大小的緩存區(qū),以便支持page flip模式,如果屏幕設(shè)備支持page flip模式,那么FramebufferNativeWindow中buffers將分別指向一個(gè)屏幕大小的屏幕設(shè)備緩存區(qū)。 [cpp]?view plaincopy? ? 1.3.2 屏幕設(shè)備不支持page flip模式
在mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp中可以得知,如果屏幕設(shè)備不支持page flip模式,那么numBuffer值將為1而不是2,那么映射過(guò)來(lái)的屏幕緩存區(qū)將只有一個(gè)屏幕大小,不夠支持page flip模式,那么此時(shí)將不使用這一個(gè)屏幕大小的屏幕緩存區(qū),而改為去dev/pmem設(shè)備去申請(qǐng)。gralloc_alloc_framebuffer_locked()@hardware/msm7k/libgralloc-qsd8k/gpu.cpp
[cpp]?view plaincopy
? ? 2. 打開Overlay
同選擇gralloc library相似,根據(jù)屬性值來(lái)選擇何時(shí)的overlay庫(kù),如果vendor廠商沒(méi)有提供overlay庫(kù)的話,那么系統(tǒng)將使用默認(rèn)的overlay庫(kù)overlay.default.so。同樣的我們獲得overlay庫(kù)的HAL_MODULE_INFO_SYM結(jié)構(gòu)體,作為系統(tǒng)調(diào)用overlay的接口。[cpp]?view plaincopy
? ? 3. 選擇OpenGL ES library(也即軟/硬件加速)
OpenGL (Open Graphics Library)[3] is a standard specification defining a cross-language, cross-platform API for writing applications that produce 2D and 3D computer graphics. The interface consists of over 250 different function calls which can be used to draw complex three-dimensional scenes from simple primitives. OpenGL was developed by Silicon Graphics Inc. (SGI) in 1992[4] and is widely used in CAD, virtual reality, scientific visualization, information visualization, flight simulation, and video games. OpenGL is managed by the non-profit technology consortium Khronos Group.。 android是默認(rèn)支持OpenGL ES軟件加速的,library為libGLES_android,源碼路徑為frameworks\base\opengl\libagl;如果手機(jī)設(shè)備支持硬件加速的話,那么復(fù)雜的圖像處理工作將交由GPU去處理,那么效率將大大提高。但是如果系統(tǒng)真的存在硬件加速,它是如何選擇何時(shí)用軟件加速?何時(shí)用硬件加速的呢? 如何查看是否有GPU來(lái)實(shí)現(xiàn)硬件加速,很容易查看/system/lib/egl/egl.cfg文件內(nèi)容 [java]?view plaincopy[cpp]?view plaincopy
? ?3.1?OpenGL初始化
在調(diào)用不管是軟件加速的還是硬件加速的OpenGL api之前,我們都需要把軟硬兩種模式的各自的OpenGL api提取出來(lái),抽象出一個(gè)interface來(lái)供系統(tǒng)使用,這個(gè)過(guò)程我稱之為OpenGL初始化過(guò)程。 軟硬兩種模式的OpenGL api被分別指定到了一個(gè)全局?jǐn)?shù)組的對(duì)應(yīng)位置。frameworks/base/opengl/libs/EGL/egl.cpp
[cpp]?view plaincopy
gEGLImpl[IMPL_HARDWARE]中保存著硬件圖形設(shè)備的OpenGL api地址,從 [cpp]?view plaincopy
這部分代碼在egl_init_drivers_locked()@frameworks/base/opengl/libs/EGL/egl.cpp
3.2 EGL和GLES api
在OpenGL的初始化過(guò)程中,OpenGL提供了兩套api,分別稱為EGL和GLES。android在OPENGL初始化過(guò)程中,會(huì)將兩種不同的接口分開管理,從下面代碼中我們可以看到EGL和GLES api地址被存儲(chǔ)到了不同的位置。 @frameworks\base\opengl\libs\EGL\Loader.h[cpp]?view plaincopy
上面枚舉的EGL表示ELG api;GLESvq1_CM表示OpenGL ES 1.0的api;GLESv2表示OpenGL ES 2.0的api。 EGL api地址最終被存儲(chǔ)在gEGLImpl[].egl中; GLESvq1_CM api地址最終被存儲(chǔ)在gEGLImpl[].hooks[GLESv1_INDEX]->gl中; GLESv2 api地址最終被存儲(chǔ)在gEGLImpl[].hooks[GLESv2_INDEX]->gl中;
3.2.1 EGL api EGL is an interface between Khronos rendering APIs such as OpenGL ES or OpenVG and the underlying native platform window system. It handles graphics context management, surface/buffer binding, and rendering synchronization and enables high-performance, accelerated, mixed-mode 2D and 3D rendering using other Khronos APIs. 上面引用了官方的定義,可以看出,EGL是系統(tǒng)和OPENGL ES之間的接口,它的聲明在文件frameworks\base\opengl\libs\EGL\egl_entries.in。
3.2.2 GLES GLES才是真正的OpenGL ES的api,它的聲明我們可以在frameworks\base\opengl\libs\entries.in找到。目前的android系統(tǒng)不但將EGL提供給系統(tǒng)使用,同時(shí)將GLES也提供給了系統(tǒng)使用,這個(gè)我們可以在最開始的顯示系統(tǒng)的結(jié)構(gòu)圖中可以看到,surfacefliger和framework的opengl模塊均可以訪問(wèn)EGL和GLES接口。
3.3 OpenGL config
每個(gè)OpenGL庫(kù)都根據(jù)不同的像素格式(pixel format)提供了一系統(tǒng)的config,android根據(jù)framebuffer中設(shè)置的像素格式來(lái)選擇合適的config,android根據(jù)中各config中的屬性信息來(lái)創(chuàng)建main surface和openGL上下文。3.3.1 系統(tǒng)默認(rèn)pixel format
當(dāng)前的代碼分析是基于gingerbread的,在mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp中我們可以找到framebuffer的pixel format的類型 [cpp]?view plaincopy目前的移動(dòng)設(shè)備都是真彩色,所以這里我們認(rèn)為我們的屏幕設(shè)備支持的是HAL_PIXEL_FORMAT_RGBA_8888。
? ??
3.3.2 config初始化
所有的OpenGL庫(kù)提供的config,同樣需要將軟硬兩種模式的各自的OpenGL config提取出來(lái)供系統(tǒng)使用,如同OpenGL api地址一樣。OpenGL config提取出來(lái)后保存在另外一個(gè)全局變量 [cpp]?view plaincopy在提取出的openGL的config時(shí),會(huì)保存到gDisplay[0].config中,在這兒有一個(gè)很tricky的實(shí)現(xiàn),它保證了硬件加速器的優(yōu)先使用!
[cpp]?view plaincopy
代碼在eglInitialize()@frameworks/base/opengl/libs/EGL/egl.cpp
3.3.3 config選擇
上文說(shuō)到,android會(huì)根據(jù)framebuffer的pixel format信息來(lái)獲取對(duì)應(yīng)的config,這個(gè)過(guò)程只選擇一個(gè)合適的config,選到為止。3.3.3.1 滿足屬性要求
并不是所有的config都可以被選擇,首先這個(gè)config的屬性需要滿足 init()@DisplayHardware.cpp[cpp]?view plaincopy
3.3.3.2 滿足RGBA要求
在pixelflinger中,為系統(tǒng)提供了各個(gè)pixel format的基本信息,RGBA值,字節(jié)數(shù)/pixel,位數(shù)/pixel。 system/core/libpixelflinger/format.cpp[cpp]?view plaincopy
selectConfigForPixelFormat()@frameworks/base/libs/ui/EGLUtils.cpp
[cpp]?view plaincopy
? ? 4. 創(chuàng)建main surface
要讓OpenGL進(jìn)行圖形處理,那么需要在OpenGL中創(chuàng)建一個(gè)openGL surface。代碼在eglCreateWindowSurface()@frameworks/base/opengl/libs/EGL/egl.cpp 調(diào)用當(dāng)前的config所處的openGL庫(kù)的api來(lái)創(chuàng)建surface。通過(guò)validate_display_config()方法來(lái)獲取當(dāng)前config的openGL api。 創(chuàng)建的surface會(huì)和FramebufferNativeWindow關(guān)聯(lián)到一起。? ? 5. 創(chuàng)建?OpenGL ES 上下文
? ??An?OpenGL context?represents many things. A context stores all of the state associated with this instance of OpenGL. It represents the (potentially visible)?default framebufferthat rendering commands will draw to when not drawing to a?framebuffer object. Think of a context as an object that holds all of OpenGL; when a context is destroyed, OpenGL is destroyed.
? ?http://www.opengl.org/wiki/OpenGL_context
?具體的創(chuàng)建過(guò)程專業(yè)術(shù)語(yǔ)太多,也沒(méi)有仔細(xì)研究不再介紹。
? ? 6. 綁定context和surface
有了surface,有了FramebufferNativeWindow,有了context,基本上與圖形系統(tǒng)相關(guān)的概念都有了,下一步就是把這幾個(gè)概念關(guān)聯(lián)起來(lái),在創(chuàng)建surface時(shí)已經(jīng)將surface和FramebufferNativeWindow關(guān)聯(lián)了起來(lái)。 eglMakeCurrent()@frameworks/base/opengl/libs/EGL/egl.cpp6.1 多線程支持
OpenGL 提供了多線程的支持,有以下2點(diǎn)的支持: 1. 一個(gè)Context只能被一個(gè)線程使用,不能存在多個(gè)線程使用同一個(gè)context。因此在多線層操作中使用到了TLS技術(shù),即Thread-local storage,來(lái)保證context被唯一使用。 makeCurrent()@frameworks/base/opengl/libs/libagl/egl.cpp[cpp]?view plaincopy
[cpp]?view plaincopy
盡管openGL 實(shí)現(xiàn)了多線程的支持,目前我從代碼中別沒(méi)有找到多線程的使用。
6.2 設(shè)置surface和context之間的關(guān)系
由于vendor廠商提供的GPU的GLES庫(kù)是不可見的,因此以libGLES_android.so軟件加速為例來(lái)說(shuō)明這個(gè)過(guò)程。 contex中保存著兩個(gè)surface,read和draw,多少情況下這兩個(gè)surface為同一個(gè)surface。 設(shè)置FramebufferNativeWindow中Buffers[2]之一為surface的數(shù)據(jù)區(qū), 通過(guò)connect()和bindDrawSurface()。最終的形態(tài)如下圖所示:在init()@DisplayHardware.cpp中,在綁定surface和context之后,馬上在當(dāng)前線程中unbind了context,通過(guò) [cpp]?view plaincopy
[cpp]?view plaincopy
下圖為這個(gè)圖形系統(tǒng)的類圖結(jié)構(gòu)。
原文地址:?http://blog.csdn.net/windskier/article/details/7030732
總結(jié)
以上是生活随笔為你收集整理的android surfaceflinger研究----显示系统的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android的窗口机制分析------
- 下一篇: android surfacefling