android surfaceflinger研究----显示系统
? 這周抽空研究了一下SurfaceFlinger,發現真正復雜的并不是SurfaceFlinger本身,而是Android的display顯示系統,網上關于這部分的介紹有不少,本不打算寫的,但是發現還是記錄一下研究代碼的過程比較好,一是能夠幫助自己理清思路,另一個原因就是以后當這塊內容忘記的時候,能快速的通過這個記錄撿起來。
? ? 一. ?android顯示系統的建立
我們看SurfaceFlinger的定義就知道,它其實是一個Thread, 因此SurfaceFlinger的初始化工作就理所當然的放在了SurfaceFlinger線程中,詳見readyToRun()@SurfaceFlinger.cpp? ??SurfaceFlinger對于顯示的管理是通過一個或多個GraphicPlane對象(目前android只實現了一個)來管理的,
@SurfaceFlinger.h
[cpp]?view plaincopy
? ? 1. FrameBuffer的建立
? ??framebuffer,確切的是說是linux下的framebuffer,,它是linux圖形顯示系統中一個與圖形硬件無關的抽象層,user完全不用考慮我們的硬件設備,而僅僅使用framebuffer就可以實現對屏幕的操作。
? ? android的framebuffer并沒有被SurfaceFlinger直接使用,而是在framebuffer外做了一層包裝,這個包裝就是FramebufferNativeWindow,我們來看一下FramebufferNativeWindow的創建過程。
? ?我們的framebuffer是由一個設備符fbDev來表示的,它是FramebufferNativeWindow的一個成員,我們來分析一下對fbDev的處理過程。
? ? 1.1. fbDev設備符
? ? 1.1.1?gralloc library
? ? 在這之前,先介紹一下gralloc library,它的形態如grallocBOARDPLATFORM.so,?BOARDPLATFORM可以從屬性ro.board.platform中獲得,這篇文章中我們以Qualcomm?msmx7x30為例,也就是gralloc.msm7x30.so中,它的源路徑在hardware/msm7k/libgralloc-qsd8k。
? ? framebuffer的初始化需要通過HAL?gralloc.msm7x30.so 來完成與底層硬件驅動的適配,但是gralloc library并不是平臺無關的,不同的vendor可能會實現自己的gralloc library,因此為了保證在創建framebuffer時能夠平臺無關,android只能是動態的判斷并使用當前的gralloc library,android通過從gralloc library中再抽象出一個hw_module_t結構來供使用,它為framebuffer的初始化提供了需要的gralloc.msm7x30.so業務。因此通過這個hw_module_t結構我們就不需要知道當前系統使用的到底是哪個gralloc library。按規定,所有gralloc library中的這個結構體被命名為HAL_MODULE_INFO_SYM(HMI)。當前分析的系統中,HAL_MODULE_INFO_SYM在hardware/msm7k/libgralloc-qsd8k/galloc.cpp。
? ? 1.1.2?打開fbDev設備符? ??
? ? 下面看如何打開?打開fbDev設備符。通過HAL_MODULE_INFO_SYM提供的gralloc.msm7x30.so的接口我們調用到了fb_device_open()@hardware/msm7k/libgralloc-qsd8kframebuffer.cpp。
[cpp]?view plaincopy
在這個函數中,主要為fbDev設備符指定一個fb_context_t實例,并通過函數mapFrameBuffer()對設備節點/dev/graphics/fb0進行操作,操作的目的有:
1.獲得屏幕設備的信息,并將屏幕信息保存在HAL_MODULE_INFO_SYM(上面代碼中的module)中。
?2. 向/dev/graphics/fb0請求page flip模式,page flip模式需要至少2個屏幕大小的buffer,page flip模式在后面介紹。目前android系統中設置為2個屏幕大小的buffer。當然屏幕設備可能不支持page flip模式。
mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp
[cpp]?view plaincopy
3. 映射屏幕設備緩存區給fbDev設備符。
mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp
[cpp]?view plaincopy
1.2 grDev設備符
在為framebuffer,也就是FramebufferNativeWindow申請內存之前,我們還要介紹一個概念,就是grDev設備符。它雖然也叫設備符,但是它和具體的設備沒有直接關系,我們看它的類型就是知道了alloc_device_t,沒錯,grDev設備符就是為了FramebufferNativeWindow管理內存使用的。為FramebufferNativeWindow提供了申請/釋放內存的接口。
? ? 1.3 FramebufferNativeWindow內存管理
FramebufferNativeWindow維護了2個buffer,? [cpp]?view plaincopy? ? 1.3.1 屏幕設備支持page filp模式
目前的android系統默認要求屏幕設備給系統映射2個屏幕大小的緩存區,以便支持page flip模式,如果屏幕設備支持page flip模式,那么FramebufferNativeWindow中buffers將分別指向一個屏幕大小的屏幕設備緩存區。 [cpp]?view plaincopy? ? 1.3.2 屏幕設備不支持page flip模式
在mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp中可以得知,如果屏幕設備不支持page flip模式,那么numBuffer值將為1而不是2,那么映射過來的屏幕緩存區將只有一個屏幕大小,不夠支持page flip模式,那么此時將不使用這一個屏幕大小的屏幕緩存區,而改為去dev/pmem設備去申請。gralloc_alloc_framebuffer_locked()@hardware/msm7k/libgralloc-qsd8k/gpu.cpp
[cpp]?view plaincopy
? ? 2. 打開Overlay
同選擇gralloc library相似,根據屬性值來選擇何時的overlay庫,如果vendor廠商沒有提供overlay庫的話,那么系統將使用默認的overlay庫overlay.default.so。同樣的我們獲得overlay庫的HAL_MODULE_INFO_SYM結構體,作為系統調用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是默認支持OpenGL ES軟件加速的,library為libGLES_android,源碼路徑為frameworks\base\opengl\libagl;如果手機設備支持硬件加速的話,那么復雜的圖像處理工作將交由GPU去處理,那么效率將大大提高。但是如果系統真的存在硬件加速,它是如何選擇何時用軟件加速?何時用硬件加速的呢? 如何查看是否有GPU來實現硬件加速,很容易查看/system/lib/egl/egl.cfg文件內容 [java]?view plaincopy[cpp]?view plaincopy
? ?3.1?OpenGL初始化
在調用不管是軟件加速的還是硬件加速的OpenGL api之前,我們都需要把軟硬兩種模式的各自的OpenGL api提取出來,抽象出一個interface來供系統使用,這個過程我稱之為OpenGL初始化過程。 軟硬兩種模式的OpenGL api被分別指定到了一個全局數組的對應位置。frameworks/base/opengl/libs/EGL/egl.cpp
[cpp]?view plaincopy
gEGLImpl[IMPL_HARDWARE]中保存著硬件圖形設備的OpenGL api地址,從 [cpp]?view plaincopy
這部分代碼在egl_init_drivers_locked()@frameworks/base/opengl/libs/EGL/egl.cpp
3.2 EGL和GLES api
在OpenGL的初始化過程中,OpenGL提供了兩套api,分別稱為EGL和GLES。android在OPENGL初始化過程中,會將兩種不同的接口分開管理,從下面代碼中我們可以看到EGL和GLES api地址被存儲到了不同的位置。 @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地址最終被存儲在gEGLImpl[].egl中; GLESvq1_CM api地址最終被存儲在gEGLImpl[].hooks[GLESv1_INDEX]->gl中; GLESv2 api地址最終被存儲在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是系統和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系統不但將EGL提供給系統使用,同時將GLES也提供給了系統使用,這個我們可以在最開始的顯示系統的結構圖中可以看到,surfacefliger和framework的opengl模塊均可以訪問EGL和GLES接口。
3.3 OpenGL config
每個OpenGL庫都根據不同的像素格式(pixel format)提供了一系統的config,android根據framebuffer中設置的像素格式來選擇合適的config,android根據中各config中的屬性信息來創建main surface和openGL上下文。3.3.1 系統默認pixel format
當前的代碼分析是基于gingerbread的,在mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp中我們可以找到framebuffer的pixel format的類型 [cpp]?view plaincopy目前的移動設備都是真彩色,所以這里我們認為我們的屏幕設備支持的是HAL_PIXEL_FORMAT_RGBA_8888。
? ??
3.3.2 config初始化
所有的OpenGL庫提供的config,同樣需要將軟硬兩種模式的各自的OpenGL config提取出來供系統使用,如同OpenGL api地址一樣。OpenGL config提取出來后保存在另外一個全局變量 [cpp]?view plaincopy在提取出的openGL的config時,會保存到gDisplay[0].config中,在這兒有一個很tricky的實現,它保證了硬件加速器的優先使用!
[cpp]?view plaincopy
代碼在eglInitialize()@frameworks/base/opengl/libs/EGL/egl.cpp
3.3.3 config選擇
上文說到,android會根據framebuffer的pixel format信息來獲取對應的config,這個過程只選擇一個合適的config,選到為止。3.3.3.1 滿足屬性要求
并不是所有的config都可以被選擇,首先這個config的屬性需要滿足 init()@DisplayHardware.cpp[cpp]?view plaincopy
3.3.3.2 滿足RGBA要求
在pixelflinger中,為系統提供了各個pixel format的基本信息,RGBA值,字節數/pixel,位數/pixel。 system/core/libpixelflinger/format.cpp[cpp]?view plaincopy
selectConfigForPixelFormat()@frameworks/base/libs/ui/EGLUtils.cpp
[cpp]?view plaincopy
? ? 4. 創建main surface
要讓OpenGL進行圖形處理,那么需要在OpenGL中創建一個openGL surface。代碼在eglCreateWindowSurface()@frameworks/base/opengl/libs/EGL/egl.cpp 調用當前的config所處的openGL庫的api來創建surface。通過validate_display_config()方法來獲取當前config的openGL api。 創建的surface會和FramebufferNativeWindow關聯到一起。? ? 5. 創建?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
?具體的創建過程專業術語太多,也沒有仔細研究不再介紹。
? ? 6. 綁定context和surface
有了surface,有了FramebufferNativeWindow,有了context,基本上與圖形系統相關的概念都有了,下一步就是把這幾個概念關聯起來,在創建surface時已經將surface和FramebufferNativeWindow關聯了起來。 eglMakeCurrent()@frameworks/base/opengl/libs/EGL/egl.cpp6.1 多線程支持
OpenGL 提供了多線程的支持,有以下2點的支持: 1. 一個Context只能被一個線程使用,不能存在多個線程使用同一個context。因此在多線層操作中使用到了TLS技術,即Thread-local storage,來保證context被唯一使用。 makeCurrent()@frameworks/base/opengl/libs/libagl/egl.cpp[cpp]?view plaincopy
[cpp]?view plaincopy
盡管openGL 實現了多線程的支持,目前我從代碼中別沒有找到多線程的使用。
6.2 設置surface和context之間的關系
由于vendor廠商提供的GPU的GLES庫是不可見的,因此以libGLES_android.so軟件加速為例來說明這個過程。 contex中保存著兩個surface,read和draw,多少情況下這兩個surface為同一個surface。 設置FramebufferNativeWindow中Buffers[2]之一為surface的數據區, 通過connect()和bindDrawSurface()。最終的形態如下圖所示:在init()@DisplayHardware.cpp中,在綁定surface和context之后,馬上在當前線程中unbind了context,通過 [cpp]?view plaincopy
[cpp]?view plaincopy
下圖為這個圖形系統的類圖結構。
原文地址:?http://blog.csdn.net/windskier/article/details/7030732
總結
以上是生活随笔為你收集整理的android surfaceflinger研究----显示系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android的窗口机制分析------
- 下一篇: android surfacefling