android surfaceflinger研究----顯示系統

 這周抽空研究了一下SurfaceFlinger,發現真正複雜的並不是SurfaceFlinger本身,而是android的display顯示系統,網上關於這部分的介紹有不少,本不打算寫的,但是發現還是記錄一下研究代碼的過程比較好,一是能夠幫助自己理清思路,另一個原因就是以後當這塊內容忘記的時候,能快速的通過這個記錄撿起來。

    一.  android顯示系統的建立

    我們看SurfaceFlinger的定義就知道,它其實是一個Thread, 因此SurfaceFlinger的初始化工作就理所當然的放在了SurfaceFlinger線程中,詳見readyToRun()@SurfaceFlinger.cpp

    SurfaceFlinger對於顯示的管理是通過一個或多個GraphicPlane對象(目前android只實現了一個)來管理的,

@SurfaceFlinger.h

  1. GraphicPlane                mGraphicPlanes[1];  
    其實,GraphicPlane類只是一個wrapper層,目的是當android支持多個顯示系統時,通過該類來管裏各自的圖形系統,顯示系統真正的初始化工作是通過DisplayHardware類來初始化底層圖形系統的管理與顯示的。真正的圖形顯示系統的初始化在init()@DisplayHardware.cpp
    目前,android支持一個圖形系統,這個圖形系統是全局的,surfaceflinger可以訪問,其他不通過surfaceflinger進行圖形處理的application也可以對其進行操作。


    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。


  1. int fb_device_open(hw_module_t const* module, const char* name,  
  2.         hw_device_t** device)  
  3. {  
  4.     int status = -EINVAL;  
  5.     if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {  
  6.         alloc_device_t* gralloc_device;  
  7.         status = gralloc_open(module, &gralloc_device);  
  8.   
  9.         /* initialize our state here */  
  10.         fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));  
  11.         memset(dev, 0, sizeof(*dev));  
  12.   
  13.         /* initialize the procs */  
  14.         dev->device.common.tag = HARDWARE_DEVICE_TAG;  
  15.   
  16.         private_module_t* m = (private_module_t*)module;  
  17.         status = mapFrameBuffer(m);  
  18.   
  19. }  

在這個函數中,主要爲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

  1. /* 
  2.  * Request NUM_BUFFERS screens (at lest 2 for page flipping) 
  3.  */  
  4. info.yres_virtual = info.yres * NUM_BUFFERS;  
  5.   
  6.   
  7. uint32_t flags = PAGE_FLIP;  
  8. if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {  
  9.     info.yres_virtual = info.yres;  
  10.     flags &= ~PAGE_FLIP;  
  11.     LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");  
  12. }  


3. 映射屏幕設備緩存區給fbDev設備符。

mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp

  1. /* 
  2.  * map the framebuffer 
  3.  */  
  4.   
  5. int err;  
  6. size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);  
  7. module->framebuffer = new private_handle_t(dup(fd), fbSize,  
  8.         private_handle_t::PRIV_FLAGS_USES_PMEM);  
  9.   
  10. module->numBuffers = info.yres_virtual / info.yres;  
  11. module->bufferMask = 0;  
  12.   
  13. void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);  
  14. if (vaddr == MAP_FAILED) {  
  15.     LOGE("Error mapping the framebuffer (%s)", strerror(errno));  
  16.     return -errno;  
  17. }  
  18. module->framebuffer->base = intptr_t(vaddr);  
  19. memset(vaddr, 0, fbSize);  


1.2 grDev設備符

在爲framebuffer,也就是FramebufferNativeWindow申請內存之前,我們還要介紹一個概念,就是grDev設備符。它雖然也叫設備符,但是它和具體的設備沒有直接關係,我們看它的類型就是知道了alloc_device_t,沒錯,grDev設備符就是爲了FramebufferNativeWindow管理內存使用的。爲FramebufferNativeWindow提供了申請/釋放內存的接口。


    1.3 FramebufferNativeWindow內存管理

    FramebufferNativeWindow維護了2個buffer, 
  1. sp<NativeBuffer> buffers[2];  

    1.3.1 屏幕設備支持page filp模式

    目前的android系統默認要求屏幕設備給系統映射2個屏幕大小的緩存區,以便支持page flip模式,如果屏幕設備支持page flip模式,那麼FramebufferNativeWindow中buffers將分別指向一個屏幕大小的屏幕設備緩存區。
  1. // create a "fake" handles for it  
  2. intptr_t vaddr = intptr_t(m->framebuffer->base);  
  3. private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,  
  4.                                              private_handle_t::PRIV_FLAGS_USES_PMEM |  
  5.                                              private_handle_t::PRIV_FLAGS_FRAMEBUFFER);  
  6.   
  7. // find a free slot  
  8. for (uint32_t i=0 ; i<numBuffers ; i++) {  
  9.     if ((bufferMask & (1LU<<i)) == 0) {  
  10.         m->bufferMask |= (1LU<<i);  
  11.         break;  
  12.     }  
  13.     vaddr += bufferSize;  
  14. }  
  15.   
  16. hnd->base = vaddr;  
  17. hnd->offset = vaddr - intptr_t(m->framebuffer->base);  
  18. *pHandle = hnd;  

    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

  1.     const uint32_t bufferMask = m->bufferMask;  
  2.     const uint32_t numBuffers = m->numBuffers;  
  3.     const size_t bufferSize = m->finfo.line_length * m->info.yres;  
  4.     if (numBuffers == 1) {  
  5.         // If we have only one buffer, we never use page-flipping. Instead,  
  6.         // we return a regular buffer which will be memcpy'ed to the main  
  7.         // screen when post is called.  
  8.         int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;  
  9.         return gralloc_alloc_buffer(bufferSize, newUsage, pHandle);  
  10.     }  


    2. 打開Overlay

    同選擇gralloc library相似,根據屬性值來選擇何時的overlay庫,如果vendor廠商沒有提供overlay庫的話,那麼系統將使用默認的overlay庫overlay.default.so。同樣的我們獲得overlay庫的HAL_MODULE_INFO_SYM結構體,作爲系統調用overlay的接口。

  1. if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {  
  2.     overlay_control_open(module, &mOverlayEngine);  
  3. }  


    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
  1. 0 0 android  
  2. 0 1 adreno200  
    因此只要我們的移動設備芯片集成了GPU,並提供了對應的GL圖形庫,那麼我們就可以在我們的工程中device目錄下的egl.cfg文件中加入類似上面的配置,那麼我們的系統就會支持硬件加速。
如adreno200 GPU提供的GL圖形庫:
  1. libGLESv1_CM_adreno200.so  
  2. libGLESv2_adreno200.so  
  3. libEGL_adreno200.so  
    那麼假如我們的系統中軟硬件加速都支持了,那麼我們從代碼來看能不能讓用戶自由的選擇加速類型,我們帶着問題來研究一下代碼。

   3.1 OpenGL初始化

    在調用不管是軟件加速的還是硬件加速的OpenGL api之前,我們都需要把軟硬兩種模式的各自的OpenGL api提取出來,抽象出一個interface來供系統使用,這個過程我稱之爲OpenGL初始化過程。
    軟硬兩種模式的OpenGL api被分別指定到了一個全局數組的對應位置。
frameworks/base/opengl/libs/EGL/egl.cpp
  1. static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];  
  1. enum {  
  2.     IMPL_HARDWARE = 0,  
  3.     IMPL_SOFTWARE,  
  4.     IMPL_NUM_IMPLEMENTATIONS  
  5. };  

gEGLImpl[IMPL_HARDWARE]中保存着硬件圖形設備的OpenGL api地址,從
  1. libGLESv1_CM_adreno200.so  
  2. libGLESv2_adreno200.so  
  3. libEGL_adreno200.so  
這3個庫中獲得;gEGLImpl[IMPL_SOFTWARE]中保存着軟件的OpenGL api地址,從libGLES_android.so中獲取。

這部分代碼在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
  1. enum {  
  2.     EGL         = 0x01,  
  3.     GLESv1_CM   = 0x02,  
  4.     GLESv2      = 0x04  
  5. };  
load_driver()@frameworks\base\opengl\libs\EGL\Loader.cpp

上面枚舉的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的類型
  1.    if(info.bits_per_pixel == 32) {  
  2. /* 
  3. * Explicitly request RGBA_8888 
  4. */  
  5.   
  6. /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do 
  7. * not use the MDP for composition (i.e. hw composition == 0), ask for 
  8. * RGBA instead of RGBX. */  
  9. if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0)  
  10.     module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;  
  11. else if(property_get("debug.composition.type", property, NULL) > 0 && (strncmp(property, "mdp", 3) == 0))  
  12.     module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;  
  13. else  
  14.     module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888;  
  15.    } else {  
  16. /* 
  17. * Explicitly request 5/6/5 
  18. */  
  19. module->fbFormat = HAL_PIXEL_FORMAT_RGB_565;  
  20.    }  

目前的移動設備都是真彩色,所以這裏我們認爲我們的屏幕設備支持的是HAL_PIXEL_FORMAT_RGBA_8888。

    

3.3.2 config初始化

所有的OpenGL庫提供的config,同樣需要將軟硬兩種模式的各自的OpenGL config提取出來供系統使用,如同OpenGL api地址一樣。OpenGL config提取出來後保存在另外一個全局變量
  1. static egl_display_t gDisplay[NUM_DISPLAYS];  
  1. //  EGLDisplay are global, not attached to a given thread  
  2. const unsigned int NUM_DISPLAYS = 1;  
中,不同於gEGLImpl分開保存軟硬件api,所有的config,不論軟硬件的,均保存在gDisplay[0],因爲所有的config是以屏幕區分的,同一塊屏幕應該保存同一份config信息。

在提取出的openGL的config時,會保存到gDisplay[0].config中,在這兒有一個很tricky的實現,它保證了硬件加速器的優先使用!

  1. <strong>  </strong>      // sort our configurations so we can do binary-searches  
  2.         qsort(  dp->configs,  
  3.                 dp->numTotalConfigs,  
  4.                 sizeof(egl_config_t), cmp_configs);<strong>  
  5. </strong>  
最終,上述代碼會將gDisplay[0].config中的配置按照先硬件的,後軟件的規則做一個總體的排序。

代碼在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
  1. // initialize EGL  
  2. EGLint attribs[] = {  
  3.         EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,  
  4.         EGL_NONE,           0,  
  5.         EGL_NONE  
  6. };  

3.3.3.2 滿足RGBA要求

在pixelflinger中,爲系統提供了各個pixel format的基本信息,RGBA值,字節數/pixel,位數/pixel。
system/core/libpixelflinger/format.cpp
  1. static GGLFormat const gPixelFormatInfos[] =  
  2. {   //          Alpha    Red     Green   Blue  
  3.     {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE  
  4.     {  4, 32, {{32,24,   8, 0,  16, 8,  24,16 }}, GGL_RGBA },   // PIXEL_FORMAT_RGBA_8888  
android會根據pixelflinger的pixel format信息,去和openGL的config比較,得到想要的config。

selectConfigForPixelFormat()@frameworks/base/libs/ui/EGLUtils.cpp
  1. EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);  
  2. if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {  
  3.     free(configs);  
  4.     return BAD_VALUE;  
  5. }  
  6.   
  7. const int fbSzA = fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);  
  8. const int fbSzR = fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);  
  9. const int fbSzG = fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);  
  10. const int fbSzB = fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE);   
  11.   
  12. int i;  
  13. EGLConfig config = NULL;  
  14. for (i=0 ; i<n ; i++) {  
  15.     EGLint r,g,b,a;  
  16.     EGLConfig curr = configs[i];  
  17.     eglGetConfigAttrib(dpy, curr, EGL_RED_SIZE,   &r);  
  18.     eglGetConfigAttrib(dpy, curr, EGL_GREEN_SIZE, &g);  
  19.     eglGetConfigAttrib(dpy, curr, EGL_BLUE_SIZE,  &b);  
  20.     eglGetConfigAttrib(dpy, curr, EGL_ALPHA_SIZE, &a);  
  21.     if (fbSzA <= a && fbSzR <= r && fbSzG <= g && fbSzB  <= b) {  
  22.         config = curr;  
  23.         break;  
  24.     }  
  25. }  

    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.cpp

6.1 多線程支持

OpenGL 提供了多線程的支持,有以下2點的支持:
1. 一個Context只能被一個線程使用,不能存在多個線程使用同一個context。因此在多線層操作中使用到了TLS技術,即Thread-local storage,來保證context被唯一使用。
makeCurrent()@frameworks/base/opengl/libs/libagl/egl.cpp
  1.     ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();  
  2.     if (gl) {  
  3.         egl_context_t* c = egl_context_t::context(gl);  
  4.         if (c->flags & egl_context_t::IS_CURRENT) {  
  5.             if (current != gl) {  
  6.                 // it is an error to set a context current, if it's already  
  7.                 // current to another thread  
  8.                 return -1;  
  9.             }  
  10.         } else {  
  11.             if (current) {  
  12.                 // mark the current context as not current, and flush  
  13.                 glFlush();  
  14.                 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;  
  15.             }  
  16.         }  
  17.         if (!(c->flags & egl_context_t::IS_CURRENT)) {  
  18.             // The context is not current, make it current!  
  19.             setGlThreadSpecific(gl);  
  20.             c->flags |= egl_context_t::IS_CURRENT;  
  21.         }  
2. 在同一進程中,對於不同的線程對OpenGL庫的訪問,可能使用的GLES api version不同,同樣可以使用TLS技術來保證多線程過程中,不同線程調用各自的GLES api。
前面我們介紹過GLES api地址被存放在gEGLImpl[].hooks[VERSION]->gl中,因此爲保證多線程支持,android將gEGLImpl[].hooks[VERSION]保存到了TLS中,這樣就實現了不同線程各自調用各自版本的GLES api。
eglMakeCurrent()@frameworks/base/opengl/libs/EGL/egl.cpp
  1. // cur_c has to be valid here (but could be terminated)  
  2. if (ctx != EGL_NO_CONTEXT) {  
  3.     setGlThreadSpecific(c->cnx->hooks[c->version]);  
  4.     setContext(ctx);  
  5.     _c.acquire();  
  6. else {  
  7.     setGlThreadSpecific(&gHooksNoContext);  
  8.     setContext(EGL_NO_CONTEXT);  
  9. }  

儘管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,通過
  1. // Unbind the context from this thread  
  2. eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);  
這麼做的目的應該是支持多display系統中的特殊處理,目的是當系統有多個display系統的話,那麼surfaceflinger就會去定義多個DisplayHardware對象,那麼爲了保證下一個DisplayHardware對象的創建不受影響,在當前的DisplayHardware創建完成後,將context從當前的進程中unbind掉。
不過沒關係,在所有的DisplayHardware創建完成之後,surfaceflinger會重新bind 主Display系統的context和surface。
readyToRun()@SurfaceFlinger.cpp
  1. // initialize primary screen  
  2. // (other display should be initialized in the same manner, but  
  3. // asynchronously, as they could come and go. None of this is supported  
  4. // yet).  
  5. const GraphicPlane& plane(graphicPlane(dpy));  
  6. const DisplayHardware& hw = plane.displayHardware();  
  7. const uint32_t w = hw.getWidth();  
  8. const uint32_t h = hw.getHeight();  
  9. const uint32_t f = hw.getFormat();  
  10. hw.makeCurrent();  



下圖爲這個圖形系統的類圖結構。


轉自:http://blog.csdn.net/windskier/article/details/7030732

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章