Chinaunix首页 | 论坛 | 博客
  • 博客访问: 396053
  • 博文数量: 53
  • 博客积分: 1910
  • 博客等级: 中尉
  • 技术积分: 1130
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-10 14:56
文章分类

全部博文(53)

文章存档

2013年(1)

2012年(17)

2011年(33)

2010年(2)

分类: 嵌入式

2012-07-12 22:17:48

1. 从 SurfaceFlinger::readyToRun 开始 (SurfaceFlinger.cpp)
   class SurfaceFlinger : 中包含下面obj
     GraphicPlane  mGraphicPlanes[1];
   UML 里称之为组合或者包容
   GraphicPlane& plane(graphicPlane(dpy)); 返回mGraphicPlanes的引用
  
   DisplayHardware* const hw = new DisplayHardware(this, dpy);
   初始化1个DisplayHardware
  
   因为每一个graphicPlane对象都对应一个DisplayHardware
   下面把他们组合起来
   plane.setDisplayHardware(hw);
 
关于这几个类之间的关系图:
 
 
  到这里SurfaceFlinger组合了GraphicPlane,然后GraphicPlane 组合了
   DisplayHardware,并且DisplayHardware 已经在 new DisplayHardware
   完成了init,与framebuffer 的关联,具体做了什么呢?
   继续看DisplayHardware
 
2. new DisplayHardware
   class DisplayHardware 构造时传入SurfaceFlinger引用
   以及它的父类 DisplayHardwareBase 的成员wp mFlinger;
   DisplayHardware 到 SurfaceFlinger 的联系也建立了
   其他dpy=0,mFlags=0到自己的类成员,开始执行init前
   给自己提个问题,虽然感觉这个成员使用SurfaceFlinger的弱引用
   满合适的,但讲不出为什么的道理???
  
   void DisplayHardware::init(uint32_t dpy)一开始就又new了这样1个类:
   class FramebufferNativeWindow :
     public EGLNativeBase                          LightRefBase>
   这个类的注释如下:
    * This implements the (main) framebuffer management. This class is used
    * mostly by SurfaceFlinger, but also by command line GL application.
  
    * In fact this is an implementation of ANativeWindow on top of
    * the framebuffer.
    *
    * Currently it is pretty simple, it manages only two buffers (the front
    * and back buffer).
    很直接说明了FramebufferNativeWindow 与 framebuffer 以及SurfaceFlinger
    之间的关系
 
    SurfaceFlinger操作的是对framebuffer又做了1次封装的FramebufferNativeWindow类
 
3.  new FramebufferNativeWindow (FramebufferNativeWindow.cpp)
    从构造函数看起:
    FramebufferNativeWindow::FramebufferNativeWindow()
    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
 
    a. 首先获得 gralloc hardware module  

    b. 执行 framebuffer_open(module, &fbDev);
       来获得struct framebuffer_device_t
      它调用下面gralloc module的open函数:
      module->methods->open(module,
            GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device);
gralloc hardware module 的open定义如下
static struct hw_module_methods_t gralloc_module_methods = {
        open: gralloc_device_open
};
      对于GRALLOC_HARDWARE_FB0,gralloc_device_open执行下面函数
       fb_device_open(module, name, device); 调用
       gralloc_open(module, &gralloc_device);
       实际对应到
       module->methods->open(module,
            GRALLOC_HARDWARE_GPU0, (struct hw_device_t**)device);
       就是 gralloc_device_open的GRALLOC_HARDWARE_GPU0部分
       主要做了下面工作:
       分配下面结构:
        struct gralloc_context_t {
           alloc_device_t  device;
           /* our private data here */
         };
        并对 alloc_device_t  device设置alloc 函数为gralloc_alloc
 free 函数为gralloc_free
 这样在获得 struct framebuffer_device_t * 前
 我们已经获得了 alloc_device_t* gralloc_device;
 注意galloc module的其他几个方法:
 registerBuffer: gralloc_register_buffer,
        unregisterBuffer: gralloc_unregister_buffer,
        lock: gralloc_lock,
        unlock: gralloc_unlock,
 这些都是以后buffer管理要用到的

 接下来继续 framebuffer_device_t  device;
 部分的open操作如下:
        分配结构
 struct fb_context_t {
            framebuffer_device_t  device;
        };
        setSwapInterval = fb_setSwapInterval;
 post            = fb_post;
 其中fb_setSwapInterval 是设置切换framebuffer的间隔,现在还没实现
        fb_post 很重要,将显示内容传到硬件缓冲区,根据其中if else 可以看出有
 两种方法
        1. 从新设置framebuffer 硬件缓冲的开始地址
            const size_t offset = hnd->base - m->framebuffer->base;
            m->info.activate = FB_ACTIVATE_VBL;
            m->info.yoffset = offset / m->finfo.line_length;
            ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info)
        2. memcpy 到 framebuffer硬件缓冲
 回到fb_device_open 接下来call mapFrameBuffer->mapFrameBufferLocked
 最重要的framebuff mmap 就在这里面,下面看下具体的:
        * 打开/dev/fb0 获得fd
        * ioctl 获得struct fb_fix_screeninfo,fb_var_screeninfo
        * 支持page flip的 NUM_BUFFERS,计算fb_var_screeninfo的yres_virtual
          然后ioctl再写入,再读更新后的fb_var_screeninfo
        * 根据module->framebuffer = new private_handle_t
        * mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
         获得frame buffer 物理地址对应的虚拟地址,并把vaddr 赋给
         module->framebuffer->base
        
        到这里framebuffer关键参数base, size都有了,通过module->framebuffer
        就可以访问到
 
    c. 继续 FramebufferNativeWindow 构造的gralloc_open(module, &grDev);
       不明白为什么前面fb_device_open调用gralloc_open的意义???
       这里可以获得alloc_device_t* 到 FramebufferNativeWindow 成员grDev
 
    d. new 两个class NativeBuffer : public EGLNativeBase<
                                    android_native_buffer_t,
                                     NativeBuffer,
                                    LightRefBase >
       到 FramebufferNativeWindow的成员  sp buffers[2];
 
    e.  grDev->alloc 前面的sp buffers[2];
       gralloc_alloc -> gralloc_alloc_framebuffer
          -> gralloc_alloc_framebuffer_locked
       没有真的分配内存,只是关联到我们前面获得的module->framebuffer->base
       private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
       private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
       // find a free slot
       for (uint32_t i=0 ; i        if ((bufferMask & (1LU<            m->bufferMask |= (1LU<            break;
        }
        vaddr += bufferSize;
        }
   
        hnd->base = vaddr;
       hnd->offset = vaddr - intptr_t(m->framebuffer->base);
       *pHandle = hnd;
       返回一个关联framebuffer 地址的 buffer_handle_t* 
       其中根据GRALLOC_USAGE_HW_FB判断,如果不支持 pageflip 需要另外分配2个buffer
       在ashmem 中
 
    f. 将 framebuffer_device_t* fbDev中的参数设置到ANativeWindow
        以后 FramebufferNativeWindow 可以访问到这些参数
            const_cast(ANativeWindow::flags) = fbDev->flags;
        const_cast(ANativeWindow::xdpi) = fbDev->xdpi;
        const_cast(ANativeWindow::ydpi) = fbDev->ydpi;
        const_cast(ANativeWindow::minSwapInterval) =
            fbDev->minSwapInterval;
        const_cast(ANativeWindow::maxSwapInterval) =
            fbDev->maxSwapInterval;
    g.  设置ANativeWindow 相关操作
        ANativeWindow::setSwapInterval = setSwapInterval;
        ANativeWindow::dequeueBuffer = dequeueBuffer;
        ANativeWindow::lockBuffer = lockBuffer;
        ANativeWindow::queueBuffer = queueBuffer;
        ANativeWindow::query = query;
        ANativeWindow::perform = perform;
       
      dequeueBuffer 用来获得一个buffer 进行后台输出
     ,queueBuffer 将已经绘制好的buffer ,切到硬件缓冲区

      fb->post(fb, handle);
 
      到这里 FramebufferNativeWindow 有了我们需要的一切必要元素
       framebuffer_device_t* fbDev;
       alloc_device_t* grDev;
    sp buffers[2];
    sp front;
   
    int32_t mNumBuffers=2;
    int32_t mNumFreeBuffers;
    int32_t mBufferHead=1;
    int32_t mCurrentBufferIndex;
    bool mUpdateOnDemand;
 
module ,dev 关联图:
 
 
 
4. 回到 DisplayHardware::init
   接下来打开overlay,如果vendor 没有提供,那么就是overlay.default.so
   if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
        overlay_control_open(module, &mOverlayEngine);
    }
   
    就是通过overlay_device_open 函数执行OVERLAY_HARDWARE_CONTROL命令
    来分配如下overlay control 结构:
    struct overlay_control_context_t {
    struct overlay_control_device_t device;
    /* our private state goes below here */
    };
    然后设置createOverlay,setPosition等函数

    再接下来就是OPENGL 的初始化部分:
    先判断debug.sf.hw 属性如果不等于0 ,那么就表示使用agl(软件gl)
     /system/lib/egl # ls
     libEGL_POWERVR_SGX530_125.so       => HW
     libGLES_android.so                 => SW  
     egl.cfg                            
     libGLESv1_CM_POWERVR_SGX530_125.so => HW
     libGLESv2_POWERVR_SGX530_125.so    => HW
static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
中的 gEGLImpl[IMPL_HARDWARE] 用于存放从HW lib 中获得的API
    struct egl_connection_t
    {
    inline egl_connection_t() : dso(0) { }
    void *              dso;
    /*GLESvq1_CM api 放到 gEGLImpl[].hooks[GLESv1_INDEX]->gl
      GLESv2 api     放到 gEGLImpl[].hooks[GLESv2_INDEX]->gl
      opengl\libs\egl_entries.in
      */
    gl_hooks_t *        hooks[2];
    EGLint              major;
    EGLint              minor;
    egl_t               egl;  /* 其中EGL api */
    };
   
    struct egl_t {
    #include "EGL/egl_entries.in"
    };
   
    egl_entries.in 中放的就是entry list
    比如:
    EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)
    根据定义
    #define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
    得到:
    EGLDisplay (* eglGetDisplay)( NativeDisplayType)
    libs/egl/loader.cpp 用来加载这些函数指针
    eglGetDisplay-> egl_init_drivers->
      egl_init_drivers_locked ->
       -> cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
          ->  dso = load_driver("EGL", tag, cnx, EGL);
              hnd = new driver_t(dso);
              // TODO: make this more automated
              hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM );
              hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 );

    EGL,和GLES都提供给系统使用,EGL是访问GLES的接口
    获得API后使用EGL 的 eglGetConfigs 函数去获得hw,sw的config
     if (cnx->egl.eglGetConfigs(
              dp->disp[i].dpy, dp->disp[i].config, n,
              &dp->disp[i].numConfigs))

    根据窗口选择config :
    selectConfigForNativeWindow

    通过eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
    创建main surface,其中mNativeWindow就是diplayhardware init中new的
    FramebufferNativeWindow
    通过 eglCreateContext 创建OpenGL ES context
   
    最后
      // Unbind the context from this thread
    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    opengl init 基本结束
    DisplayHardware 的如下成员都获得了相应的结果
    EGLDisplay      mDisplay;
    EGLSurface      mSurface;
    EGLContext      mContext;
    EGLConfig       mConfig;
    最重要的就是 EGLSurface      mSurface;
    以后所有的SurfaceFlinger进程中使用EGL的所有的操作目的地都是它
 
5. 回到  SurfaceFlinger::readyToRun
   接下来分配控制块,(和display相关的control block)
    // create the shared control-block
    mServerHeap = new MemoryHeapBase(4096,
    MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
   然后如注释initialize primary screen
    const GraphicPlane& plane(graphicPlane(dpy));
    const DisplayHardware& hw = plane.displayHardware();
    const uint32_t w = hw.getWidth();
    const uint32_t h = hw.getHeight();
    const uint32_t f = hw.getFormat();
    hw.makeCurrent();
    获得surfacefling  成员mGraphicPlanes[0] 的引用,
    并用该引用获得与该GraphicPlane类对象 对应的 DisplayHardware的类对象的引用
    最后通过EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
                            EGLSurface read, EGLContext ctx)
    将上面unbind 的进行context 和 mSurface 进行重新bind

    // initialize the shared control block
    这个共享控制块是4K
    结构如下:
    //管理系统中所有的显示屏 
     struct surface_flinger_cblk_t   // 4KB max 
     {
     /* 每一个bit表示一个显示屏   ,上面定义最大4个*/
    uint8_t         connected;    
    uint8_t         reserved[3];
    uint32_t        pad[7];
    display_cblk_t  displays[SharedBufferStack::NUM_DISPLAY_MAX];
     };

    接下来继续 Initialize OpenGL|ES
    好象是视口等设置,不是很懂,有时间可以看下 opengl方面的东西来了解
 
    最后开启动画显示
    // start boot animation
    property_set("ctl.start", "bootanim");
结束
 

 
阅读(4538) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~