android overlay based on msm8930

来源:互联网 发布:怎样查看电脑usb端口 编辑:程序博客网 时间:2024/05/22 07:01

   本文重点针对HDMIandroid上的应用,而比较相关的就是overlay机制。overlay在这里只是简单的介绍,后续会有文章再专门详述。

      我没记错的话,高通从7X30开始,平台就可以支持HDMI1.3)输出了。只不过在7x30上通过RGB接口外接一颗HDMItransmitter来实现;而到了8系列(8x60),高通把这颗IC也集成了,直接就提供HDMI的输出了。(这样下去,以后渐渐的把外围器件都集成了,做底层的估计要失业了,做硬件的似乎工作量也没多少了)。

       先来看看HW的能力,下图是MDP4.0的结构图:

       

可以看到,MDP4内部有4overlay pipe2个是for UIRGB)的,2个是VG for videographics的;另外有2mixermixer1for primary display的(可以是MDDI接口的,也可以是RGB接口的lcdoled等);mixer2for external display的,如通过RGB interface2外接HDMI transmitterTV,也可以是NTSC/PAL等模拟电视信号。

        NoteVG1RGB1mixer1混合到primary lcdVG2RGB2mixer2混合到external LCD(如HDMI TV

        如果是MDP4.1的话,MDDI接口被移除了,另外RGB接口只有一个,另一个内部集成为HDMI接口了。

     

      上面提到的是硬件平台相关的,就是说硬件有支持HDMI输出的能力,但是软件的状况呢?我们来看看Android和高通的状况。

      关于HDMI本身,我就不介绍了,网上随便找找都可以看明白。

      研究过Android的都知道,surfacefinger负责管理应用程序的显示窗口,每个窗口可以由多个surface组成,surfaceflinger通过OpenGL(可以通过HW,也可以是SW)把所有的surface合成后,通过调用gralloc模块或是overlay模块(MDP4.X才支持)把整屏数据送到显示设备上。可是Android(截止到2.23.0的状况还未知)上目前只支持一个显示设备,也就是说在surfaceflinger只能固定一个显示设备,那么HDMI这个应用在android手机上如何应用呢?

     这里介绍2个做法,一个是高通给做好的,叫做UI mirroringvideo mirroring;另一个就是我们自己添加接口,AP自己来实现想要的功能。

     先来看高通在android中的做法,根据字面不难理解,UI mirroringvideo mirroring其实就是把原来显示在primary LCD上的数据mirrorHDMI接口。下图为软件框架图:

      

     先来看看HDMI的控制方面,上图的右侧,user空间中有一个HDMI service,包含一个listener(都是java的),当HDMI cable插入后,底层HDMI的驱动检测到(HPD)后,通过kobject_uevent传送给HDMI daemondaemon再把event发送给HDMIserviceHDMI service除了判断这个eventcable状态),另外还要判断qualcomm settingHDMIon/off选项,然后把判断结果broadcast给各个AP,各个AP也就知道当前是否要开启HDMI输出了

      接着先看UI mirroring(不含video的状况)的实现,它针对的是界面的操作,数据为RGB格式。我们知道在kernel中每个显示设备都对应一个fb,初始化时都会分配framebuffer,在这里,primary lcd对应fb0设备,HDMI对应fb1设备。正常情况下,surfaceflinger合成好一个main surface后,通过post buffergralloc模块)把数据放入fb0,然后,通过overlaykernel下做的,上层看到的还是通过IOCRLFBIOPUT_VSCREENINFO命令实现)输出到primary lcd;当平台支持HDMI并且UI mirroring开启时,gralloc中(framebuffer.cpp)初始化时会多创建一个taskhdmi_ui_loop),并新建一个overlay(主要是控制和数据,参考overlaylib.h),这个overlay对应的channel固定为fb1src fd就是fb0,也就是说这个overlay的源数据就是fb0,也就是primary lcd上的数据,通过rotator进行旋转(电视是横屏),然后在overlay中再scale up后再通过HDMI送到TV。这样看来,送到HDMI上的数据其实就是把fb0中的数据copybit了一份并放大,多少会有些失真的,但对于UI界面来说是可以接受的。上述整个过程,surfaceflinger是不参与的。

       再来看video mirroring是怎么做的?

       先来看看什么是video mirroring,其实就是手机播放视频,同时通过HDMI输出到TV上,手机上的内容分为2个部分,一个是视频本身部分,另一个是UI,这已经占用2overlay pipe了(一个VG pipe,一个RGB pipe),TV上视频部分肯定是需要一个VG pipe,另外,由于视频大小问题,视频不可能正好为全屏模式,这样必须还需要一个RGB pipe来实现一个背景(全黑)。4pipe都被占用了,没有多余的pipe来把UI部分传到TV上,所以再使用高通平台时候,进行video mirroring时,TV上只能播放视频画面,UI部分(如菜单)在TV上是无法显示的。

        接着来看video部分是怎么处理的?首先手机端UI部分的处理模式不变,只不过上面提到的hdmi_ui_loop这个task会被停掉(UI不需要送到HDMI,原因上面已经解释过);video部分的frame通过opencore解码出来后,首先会通过surfaceflinger来创建overlay(参考layerbuffer.cpp),当系统支持HDMI时通过create overlay都会创建2个通道(这里是2VG通道),其中包含2control channel2data channel,它们的HAL层接口都再overlaylib.cpp中,channel0 for fb0channel1 for fb1,如果需要旋转,则从系统pmem中再分配对应的内存。APoverlay基本上的流程是这样的(可以参考overlays.cpp,里面不全,我补充了一些):


    sp<SurfaceComposerClient> client = new SurfaceComposerClient();//新建surface客户端

    // create pushbuffer surface
    sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240, 
            PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);//
创建一个surface

    // get to the isurface
    sp<ISurface> isurface = Test::getISurface(surface);//
得到surface相关接口
    printf("isurface = %p\n", isurface.get());
    
    // now request an overlay
    sp<OverlayRef> ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);//
创建overlay,并得到控制通道
    sp<Overlay> overlay = new Overlay(ref);//初始化overlay并得到数据通道

    overlay->setFd(mFd);//设置src datafd

    overlay->setCrop(x,y,w,h);//设置剪裁信息(根据需要)

    overlay->queueBuffer(offset);//设置显示数据的偏移

     这样video player没解码出一个frame,都会调用quene函数把数据送入2个数据通道,overlay engine会把数据送到2个显示设备。

     关于那个背景,暂时在code中还没发现,也许是因为目前的版本不是最终版本,后续还会更新。

    上面的做法是高通的;但它是有限制的,比如说无法在2个屏幕上显示不同的内容。如果我们要做,也是可以的,主要就是看AP怎么定义规则了。另外framework中需要添加接口,主要是提供一个针对fb1设备的控制接口,同样也是绕过surfaceflinger。比如说手机在播放一个影片,通过HDMI把影片传送到TV上,同时手机端可以去浏览网页。这个功能可以这样做,AP背景播放影片,得到的frame不送到primary display上,而是通过新加的接口输出到fb1设备上,而browserUI正常显示即可。如果是在高通平台去实现的话,需要把qualcomm setting里面的HDMI选项关掉,否则高通的做法和你自己AP的做法就乱套了。不过目前看,高通提供的方式似乎也可以满足应用了,但应用是永无止境的,只要user有这样的需求,developer就要去做,呵呵!


OVERLAY

首次post后仍会更新,转载请注明出处http://blog.csdn.net/zirconsdu/article/details/8773263

File Orgnization

目录/hardware/qcom/display/liboverlay/

Android.mk

mdpRotator.cpp               Overlay Rotator Wrpper

mdpWrapper.h                 MDP Normal and Overlay FrameBuffer IOCTL Wrapper

mdssRotator.cpp             Overlay MDSS Rotator Wrapper

overlay.cpp        Overlay Top level implementation file

overlay.h             Overlay Top level declaration file

overlayCtrl.cpp   OverlayCtrl implementation file

overlayCtrlData.h       OverlayCtrl and OverlayData declaration file including OverlayData implementation

overlayImpl.h    Overlay implementation which operates overlay pipes pair(LayerMixer)              

overlayMdp.cpp    Overlay implementation on MDP, used by OverlayCtrlData    

overlayMdp.h   Overlay on MDP

overlayMem.h  Overlay VG pipe input kernel memory file descriptor, maybe graphic buffer or rotator output buffer

overlayRotator.cpp         Overlay Rotator top level implementation

overlayRotator.h              Overlay Rotator top level declaration

overlayState.h  Overlay state machine

overlayUtils.cpp                 Overlay Utils

overlayUtils.h    Overlay Utils

pipes/   Overlay Pipes, that is Overlay channel. It is a VG and RGB pipe pair on MDP.

 

Platform architecture

MDP中每个VGRGB pipe pair作为一个LayerMixer的输入,由LayerMixer完成Overlay功能,作为一个Overlay channel

当使用Overlay功能时:

RGB pipe的输入是普通的Framebuffer,是Surfaceflinger的合成输出;

VG的输入是videographicscamera图像等,是内核空间内存buffer,其owner一般是VideoGraphicsV4L2等。当其前端是Rotator时,Rotator的输入是这些bufferRotator的输出Overlay rotator frame buffer作为VG的输入。

每个Overlay Channel结构如下图所示

关于Overlay Buffer(FrameBuffer RotatorBuffer OverlayBuffer)这些名称并不特别明确,只要明白Overlay Channel数据流路上的各输入输出Buffer的位置和作用即可。

下面以Layermixer1(对应/dev/graphics/fb0)为参考详述各buffer:

只UI显示时,

Framebuffer是fb0的framebuffer,是从启动时预留出的bootmem中的分配出来的。LayerMixer1处于BLT模式,Layermixer1和DMA_P(Primary display driver)分离,可以由软件完全控制。该Framebuffer做为DMA_P的输入,经MIPI_DSI输出到主屏上。

启用Overlay时,

上述Framebuffer做为RGB1 pipe的输入,而视频或图像的内核buffer做为VG pipe的输入,二者经Layermixer1合成;此时LayerMixer1工作在非BLT模式,LayerMixer1和DMA_P attach在一起,LayerMixer1输出控制参数直接提供给DMA_P使用。此时LayerMixer1仍有两种工作模式,FrameBuffer模式和DIRECT_OUT模式,前者时LayerMixer1和DMA_P之间使用一个overlaydouble buffer做缓冲,输出给DMA_P;DIRECT_OUT模式下不使用该ovl double buffer,LayerMixer1直接输出给DMA_P

一般VGRGB的输入都可以是double bufferping-pang;LayerMixer的输出也是double buffer。DMA_P/S/E做为display driver传输前端buffer作为后端接口控制器的输入。

下面两图是QC MDP UI mirrorVideo mirror时的两结构图,并没有明确画出LayerMix1Overlay流程路径,个别bufferowner可能也有所差错,buffer也并不全,仅是大致描述Overlay及其部分buffer

 

MDPDSI和后端显示控制器和接口的连接结构如下图。

 

Layer architecture

Overlay   ->  OverlayImpl

OverlayCtrlData

OverlayMDPCtrlData

MDPWrapper

FrameBuffer

 

KeyPoint

Ctrl用来设置overlay channel的参数,Data用来提交bufferOverlay channel queue。其实使用overlay本质上就是设置好pin路由,设置好通道工作参数,然后不停的提交数据让Overlay Enginee工作。MDPOverlay Channel并没有别的特殊的编程接口,都是使用控制、状态和数据寄存器来访问。其实MDP提供了远比Android Overlay实现强得多的Overlay功能。

Some flow

Ctrl::commit()  ->  MDPCtrl::set() -> mdp_wrapper::setOverlay()  -> ioctl(fd, MSMFB_OVERLAY_SET, &ov)

-> msm_fb -> mdp4_overlay设置Overlay工作参数。

Data::queueBuffer -> MDPData::play -> mdp_wrapper::play() -> ioctl(fd, MSMFB_OVERLAY_PLAY, &od)

-> msm_fb -> mdp4_overlay进行Overlay合成。注意queueBuffer第一参数fd是memFd,是内核空间的buffer,并不在用户空间和内核空间拷贝buffer数据。作用与framebuffer类似的是提交内核空间的该buffer到Overlay Enginee Queue。

有了这些平台相关知识,msm_fbmdp4_overlay驱动的功能也就容易理解了。

android gralloc流程分析for msm8960

原文转载自http://blog.csdn.net/g_salamander/article/details/8424334

增加了Gralloc模块的平台背景和功能概述部分。

对原文针对msm8960 android display做了修正。

增加了Surfaceflinger初始化FrameBufferNativeWindow的代码部分。

平台中内存有ashmen、PMEM等多种内存类型,为了Video、Graphics、GPU内存访问的需要,android引入Gralloc模块实现内存的管理。Gralloc把FrameBuffer的分配也纳入了其中,并且新引入ION做为Gralloc的非FrameBuffer内存的分配器。ION对于内核态内存在用户进程之间的访问和硬件平台模块之间数据流转提供了高效的解决方案。

Android 中 lcd 是一个帧缓冲设备,驱动程序通过处理器的 lcd 控制器将物理内存的一段区域设置为显存,如果向这段内存区域写入数据就会马上在 lcd 上显示出来。Android 在 HAL 中提供了gralloc 模块,封装了用户层对帧缓冲设备的所有操作接口,并通过 SurfaceFlinger 服务向应用提供显示支持。在启动过程中系统会加载 gralloc 模块,然后打开帧缓冲设备,获取设备的各种参数并完成 gralloc 模块的初始化。当应用程序需要把内容显示到 lcd 上时,需要通过 gralloc 模块申请一块图形缓冲区,然后将这块图形缓冲区映射到自己的地址空间并写入内容即可。当应用程序不再需要这块图形缓冲区时需要通过 gralloc 模块释放掉,然后解除对缓冲区的映射。

1、基础数据结构

gralloc 模块通过 struct private_module_t 来描述,该结构定义如下:

[cpp] view plaincopy
  1. <span style="font-size:12px;">struct private_module_t {  
  2.     gralloc_module_t base;  
  3.   
  4.     private_handle_t* framebuffer;  /* 指向图形缓冲区的句柄 */  
  5.     uint32_t flags;                 /* 用来标志系统帧缓冲区是否支持双缓冲 */  
  6.     uint32_t numBuffers;            /* 表示系统帧缓冲的个数 */  
  7.     uint32_t bufferMask;            /* 记录系统帧缓冲的使用情况 */  
  8.     pthread_mutex_t lock;           /* 保护结构体private_module_t的并行访问 */  
  9.     buffer_handle_t currentBuffer;  /* 描述当前正在被渲染的图形缓冲区 */  
  10.     int pmem_master;                /* pmem设备节点的描述符 */  
  11.     void* pmem_master_base;         /* pmem的起始虚拟地址 */  
  12.   
  13.     struct fb_var_screeninfo info;  /* lcd的可变参数 */  
  14.     struct fb_fix_screeninfo finfo; /* lcd的固定参数 */  
  15.     float xdpi;                     /* x方向上每英寸的像素数量 */  
  16.     float ydpi;                     /* y方向上每英寸的像素数量 */  
  17.     float fps;                      /* lcd的刷新率 */  
  18.       
  19.     int orientation;                /* 显示方向 */  
  20.   
  21.     enum {  
  22.         PRIV_USAGE_LOCKED_FOR_POST = 0x80000000  /* flag to indicate we'll post this buffer */  
  23.     };  
  24. };</span>  
该结构的成员记录了 gralloc 模块的各种参数,主要为模块自己使用,应用程序操作的图形缓冲区的数据结构是struct private_handle_t,定义如下:
[cpp] view plaincopy
  1. <span style="font-size:12px;">#ifdef __cplusplus  
  2. struct private_handle_t : public native_handle {  
  3. #else  
  4. struct private_handle_t {  
  5.     struct native_handle nativeHandle;  /* 用来描述一个本地句柄值 */  
  6. #endif  
  7.       
  8.     enum {  
  9.         PRIV_FLAGS_FRAMEBUFFER    = 0x00000001,  
  10.         PRIV_FLAGS_USES_PMEM      = 0x00000002,  
  11.         PRIV_FLAGS_USES_MMEM      = 0x00000004,  
  12.         PRIV_FLAGS_NEEDS_FLUSH    = 0x00000008,  
  13.     };  
  14.   
  15.     enum {  
  16.         LOCK_STATE_WRITE     =   1<<31,  
  17.         LOCK_STATE_MAPPED    =   1<<30,  
  18.         LOCK_STATE_READ_MASK =   0x3FFFFFFF  
  19.     };  
  20.   
  21.     /* 指向一个文件描述符,这个文件描述符要么指向帧缓冲区设备,要么指向一块匿名共享内存 
  22.      * 取决于private_handle_t描述的图形缓冲区是在帧缓冲区分配的,还是在内存中分配的 */  
  23.     int     fd;  
  24.     /* 指向一个魔数,它的值由静态成员变量sMagic来指定,用来标识一个private_handle_t结构体 */  
  25.     int     magic;  
  26.     /* 用来描述一个图形缓冲区的标志,它的值要么等于0,要么等于PRIV_FLAGS_FRAMEBUFFER 
  27.      * 当一个图形缓冲区的标志值等于PRIV_FLAGS_FRAMEBUFFER的时候,就表示它是在帧缓冲区中分配的 */  
  28.     int     flags;  
  29.     int     size;   /* 描述一个图形缓冲区的大小 */  
  30.     int     offset; /* 描述一个图形缓冲区的偏移地址 */  
  31.   
  32.     int     phys;   /* 图形缓冲区或帧缓冲的起始物理地址 */  
  33.     int     base;   /* 图形缓冲区或帧缓冲的起始虚拟地址 */  
  34.     int     lockState;  
  35.     int     writeOwner;  
  36.     int     pid;    /* 描述一个图形缓冲区的创建者的PID */  
  37.   
  38. #ifdef __cplusplus  
  39.     static const int sNumInts = 9;  /* 有9个整数变量 */  
  40.     static const int sNumFds = 1;   /* 有1个文件描述符 */  
  41.     static const int sMagic = 0x3141592;  
  42.   
  43.     private_handle_t(int fd, int size, int flags) :  
  44.         fd(fd), magic(sMagic), flags(flags), size(size), offset(0),  
  45.         phys(0), base(0), lockState(0), writeOwner(0), pid(getpid())  
  46.     {  
  47.         version = sizeof(native_handle);  
  48.         numInts = sNumInts;  
  49.         numFds = sNumFds;  
  50.     }  
  51.     ~private_handle_t() {  
  52.         magic = 0;  
  53.     }  
  54.   
  55.     bool usesPhysicallyContiguousMemory() {  
  56.         return (flags & PRIV_FLAGS_USES_PMEM) != 0;  
  57.     }  
  58.   
  59.     /* 用来验证一个native_handle_t指针是否指向了一个private_handle_t结构体 */  
  60.     static int validate(const native_handle* h) {  
  61.         const private_handle_t* hnd = (const private_handle_t*)h;  
  62.         if (!h || h->version != sizeof(native_handle) ||  
  63.                 h->numInts != sNumInts || h->numFds != sNumFds ||  
  64.                 hnd->magic != sMagic)   
  65.         {  
  66.             LOGE("invalid gralloc handle (at %p)", h);  
  67.             return -EINVAL;  
  68.         }  
  69.         return 0;  
  70.     }  
  71.   
  72.     static private_handle_t* dynamicCast(const native_handle* in) {  
  73.         if (validate(in) == 0) {  
  74.             return (private_handle_t*) in;  
  75.         }  
  76.         return NULL;  
  77.     }  
  78. #endif  
  79. };</span>  

图形缓冲区的操作接口由结构 struct gralloc_module_t 定义:

[cpp] view plaincopy
  1. <span style="font-size:12px;">typedef struct gralloc_module_t {  
  2.     struct hw_module_t common;  
  3.   
  4.     /* 注册一个图形缓冲区,这个指定的图形缓冲区使用一个buffer_handle_t句柄来描述 */  
  5.     int (*registerBuffer)(struct gralloc_module_t const* module,  
  6.             buffer_handle_t handle);  
  7.   
  8.     /* 注销一个图形缓冲区 */  
  9.     int (*unregisterBuffer)(struct gralloc_module_t const* module,  
  10.             buffer_handle_t handle);  
  11.   
  12.     /* 用来锁定一个图形缓冲区并将缓冲区映射到用户进程 
  13.      * 在锁定一块图形缓冲区的时候,可以指定要锁定的图形绘冲区的位置以及大小 
  14.      * 这是通过参数l、t、w和h来指定的,其中,参数l和t指定的是要访问的图形缓冲区的左上角位置 
  15.      * 而参数w和h指定的是要访问的图形缓冲区的宽度和长度 
  16.      * 锁定之后,就可以获得由参数参数l、t、w和h所圈定的一块缓冲区的起始地址,保存在输出参数vaddr中 
  17.      * 另一方面,在访问完成一块图形缓冲区之后,需要解除这块图形缓冲区的锁定 */  
  18.     int (*lock)(struct gralloc_module_t const* module,  
  19.             buffer_handle_t handle, int usage,  
  20.             int l, int t, int w, int h,  
  21.             void** vaddr);  
  22.   
  23.     int (*unlock)(struct gralloc_module_t const* module,  
  24.             buffer_handle_t handle);  
  25.   
  26.     int (*perform)(struct gralloc_module_t const* module,  
  27.             int operation, ... );  
  28.   
  29.     /* reserved for future use */  
  30.     void* reserved_proc[7];  
  31. } gralloc_module_t;</span>  

gralloc 设备则用结构 struct alloc_device_t 来描述,其定义如下:

[cpp] view plaincopy
  1. <span style="font-size:12px;">typedef struct alloc_device_t {  
  2.     struct hw_device_t common;  
  3.   
  4.     /* 申请图形缓冲区的内存空间 */      
  5.     int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride);  
  6.   
  7.     /* 释放图形缓冲区的内存空间 */  
  8.     int (*free)(struct alloc_device_t* dev,buffer_handle_t handle);  
  9. } alloc_device_t;</span>  
帧缓冲设备则采用结构 struct framebuffer_device_t 描述:
[cpp] view plaincopy
  1. <span style="font-size:12px;">typedef struct framebuffer_device_t {  
  2.     struct hw_device_t common;  
  3.   
  4.     const uint32_t  flags;  /* 用来记录系统帧缓冲区的标志 */  
  5.   
  6.     const uint32_t  width;  /* lcd显示区域的像素点数 */  
  7.     const uint32_t  height;  
  8.   
  9.     const int       stride; /* 描述设备显示屏的一行有多少个像素点 */  
  10.   
  11.     /* 描述系统帧缓冲区的像素格式,主要有HAL_PIXEL_FORMAT_RGBX_8888和HAL_PIXEL_FORMAT_RGB_565两种 */  
  12.     const int       format;  
  13.   
  14.     const float     xdpi;  
  15.     const float     ydpi;  
  16.     const float     fps;              /* lcd刷新率 */  
  17.     const int       minSwapInterval;  /* 交换两帧图像的最小间隔时间 */  
  18.     const int       maxSwapInterval;  /* 交换两帧图像的最大间隔时间 */  
  19.   
  20.     int reserved[8];  
  21.   
  22.     /* 设置帧交换间隔 */  
  23.     int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);  
  24.   
  25.     /* 设置帧缓冲区的更新区域 */  
  26.     int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);  
  27.   
  28.     /* 用来将图形缓冲区buffer的内容渲染到帧缓冲区中去,即显示在设备的显示屏中去 */  
  29.     int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);  
  30.   
  31.     /* 用来通知fb设备device,图形缓冲区的组合工作已经完成 */  
  32.     int (*compositionComplete)(struct framebuffer_device_t* dev);  
  33.   
  34.     void* reserved_proc[8];  
  35. } framebuffer_device_t;</span>  
其中成员函数 post对应用程序来说是最重要的接口,它将完成数据写入显存的工作。

2、gralloc 模块

HAL 中通过 hw_get_module 接口加载指定 id 的模块,并获得一个 hw_module_t 结构来打开设备,流程如下:  

[cpp] view plaincopy
  1. <span style="font-size:12px;">#define HAL_LIBRARY_PATH1 "/system/lib/hw"  
  2. #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"  
  3.   
  4. static const char *variant_keys[] = {  
  5.     "ro.hardware",  /* This goes first so that it can pick up a different file on the emulator. */  
  6.     "ro.product.board",  
  7.     "ro.board.platform",  
  8.     "ro.arch"  
  9. };  
  10.   
  11. static const int HAL_VARIANT_KEYS_COUNT =  
  12.     (sizeof(variant_keys)/sizeof(variant_keys[0]));  
  13.   
  14. int hw_get_module(const char *id, const struct hw_module_t **module)   
  15. {  
  16.     int status;  
  17.     int i;  
  18.     const struct hw_module_t *hmi = NULL;  
  19.     char prop[PATH_MAX];  
  20.     char path[PATH_MAX];  
  21.   
  22.     /* 
  23.      * Here we rely on the fact that calling dlopen multiple times on 
  24.      * the same .so will simply increment a refcount (and not load 
  25.      * a new copy of the library). 
  26.      * We also assume that dlopen() is thread-safe. 
  27.      */  
  28.   
  29.     /* Loop through the configuration variants looking for a module */  
  30.     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {  
  31.         if (i < HAL_VARIANT_KEYS_COUNT) {  
  32.             if (property_get(variant_keys[i], prop, NULL) == 0) {  /* 读取variant_keys数组指定的属性值 */  
  33.                 continue;  
  34.             }  
  35.             snprintf(path, sizeof(path), "%s/%s.%s.so",  /* 格式化模块名和路径,如:/system/lib/hw/gralloc.xxx.so */  
  36.                     HAL_LIBRARY_PATH1, id, prop);  
  37.             if (access(path, R_OK) == 0) break;  
  38.   
  39.             snprintf(path, sizeof(path), "%s/%s.%s.so",  
  40.                      HAL_LIBRARY_PATH2, id, prop);  
  41.             if (access(path, R_OK) == 0) break;  
  42.         } else {  
  43.             snprintf(path, sizeof(path), "%s/%s.default.so",  
  44.                      HAL_LIBRARY_PATH1, id);  
  45.             if (access(path, R_OK) == 0) break;  
  46.         }  
  47.     }  
  48.   
  49.     status = -ENOENT;  
  50.     if (i < HAL_VARIANT_KEYS_COUNT+1) {  
  51.         /* load the module, if this fails, we're doomed, and we should not try to load a different variant. */  
  52.         status = load(id, path, module);                 /* 加载模块 */  
  53.     }  
  54.   
  55.     return status;  
  56. }</span>  

可以看出,是使用id和系统平台的名字组合出so的文件名,去设定的目录动态加载该库文件然后解析特定符号,找到hw_module_t object

函数会在 /system/lib/hw 或者 /vendor/lib/hw 目录中去寻找gralloc.xxx.so 文件,如果找到了就调用load接口完成加载。

最终会调用 gralloc_device_open完成 gralloc 设备成员的初始化:

[cpp] view plaincopy
  1. <span style="font-size:12px;">int gralloc_device_open(const hw_module_t* module, const char* name,  
  2.         hw_device_t** device)  
  3. {  
  4. 98    int status = -EINVAL;  
  5. 99    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {  
  6. 100        const private_module_t* m = reinterpret_cast<const private_module_t*>(  
  7. 101            module);  
  8. 102        gpu_context_t *dev;  
  9. 103        IAllocController* alloc_ctrl = IAllocController::getInstance();  
  10. 104        dev = new gpu_context_t(m, alloc_ctrl);  
  11. 105        *device = &dev->common;  
  12. 106        status = 0;</span>  
[cpp] view plaincopy
  1. <span style="font-size:12px;">  } else {  
  2.         status = fb_device_open(module, name, device);  
  3.     }  
  4.   
  5.     return status;  
  6. }</span>  
可以认为Gralloc module中有两个设备gpu_alloc_device和fb_device,前者用于分配GPU0使用的内存和FB内存,GPU0内存管理使用ION allocator;后者用于获取分配Framebuffer Info并操作fb。
在 android 系统中,所有的图形缓冲区都是由 SurfaceFlinger服务分配的,在系统帧缓冲区中分配的图形缓冲区只在 SurfaceFlinger 服务中使用,而在内存中分配的图形缓冲区既可以在 SurfaceFlinger 服务中使用,也可以在其它的应用程序中使用,当应用程序请求 SurfaceFlinger 服务分配图形缓冲区时会发生两次映射:服务所在的进程首先会将申请到的缓冲区映射至服务的地址空间,然后应用程序使用这个图形缓冲时再将其映射至应用程序的地址空间。分配函数的实现如下:
 
[cpp] view plaincopy
  1. <span style="font-size:12px;">static int gralloc_alloc_framebuffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)  
  2. {  
  3.     private_module_t* m = reinterpret_cast<private_module_t*>(  
  4.             dev->common.module);  
  5.     pthread_mutex_lock(&m->lock);  
  6.     int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);  
  7.     pthread_mutex_unlock(&m->lock);  
  8.     return err;  
  9. }  
  10.   
  11. static int gralloc_alloc_buffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)  
  12. {  
  13. 127    int err = 0;  
  14. 128    int flags = 0;  
  15. 129    size = roundUpToPageSize(size);  
  16. 130    alloc_data data;  
  17. 131    data.offset = 0;  
  18. 132    data.fd = -1;  
  19. 133    data.base = 0;  
  20. 134    data.size = size;  
  21. 135    if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED)  
  22. 136        data.align = 8192;  
  23. 137    else  
  24. 138        data.align = getpagesize();  
  25. 139    data.pHandle = (unsigned int) pHandle;  
  26. 140    err = mAllocCtrl->allocate(data, usage);  
  27. 141  
  28. 142    if (!err) {  
  29. 143        /* allocate memory for enhancement data */  
  30. 144        alloc_data eData;  
  31. 145        eData.fd = -1;  
  32. 146        eData.base = 0;  
  33. 147        eData.offset = 0;  
  34. 148        eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));  
  35. 149        eData.pHandle = data.pHandle;  
  36. 150        eData.align = getpagesize();  
  37. 151        int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;  
  38. 152        int eDataErr = mAllocCtrl->allocate(eData, eDataUsage);  
  39. 153        ALOGE_IF(eDataErr, "gralloc failed for eData err=%s", strerror(-err));  
  40. 154  
  41. 155        if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) {  
  42. 156            flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;  
  43. 157        }  
  44. 158  
  45. 159        if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {  
  46. 160            flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;  
  47. 161            //The EXTERNAL_BLOCK flag is always an add-on  
  48. 162            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) {  
  49. 163                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;  
  50. 164            }  
  51. 165            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) {  
  52. 166                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC;  
  53. 167            }  
  54. 168        }  
  55. 169  
  56. 170        flags |= data.allocType;  
  57. 171        int eBaseAddr = int(eData.base) + eData.offset;  
  58. 172        private_handle_t *hnd = new private_handle_t(data.fd, size, flags,  
  59. 173                bufferType, format, width, height, eData.fd, eData.offset,  
  60. 174                eBaseAddr);  
  61. 175  
  62. 176        hnd->offset = data.offset;  
  63. 177        hnd->base = int(data.base) + data.offset;  
  64. 178        *pHandle = hnd;  
  65. 179    }  
  66. 180  
  67. 181    ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));  
  68. 182  
  69. 183    return err;      
  70. 184}  
  71.   
  72. /*****************************************************************************/  
  73.   
  74. static int gralloc_alloc(alloc_device_t* dev,int w, int h, int format, int usage,  
  75.                             buffer_handle_t* pHandle, int* pStride)  
  76. {  
  77.     if (!pHandle || !pStride)  
  78.         return -EINVAL;  
  79.   
  80.     size_t size, stride;  
  81.   
  82.     int align = 4;  
  83.     int bpp = 0;  
  84.     switch (format) {  /* 一个像素点占用的字节数 */  
  85.         case HAL_PIXEL_FORMAT_RGBA_8888:  
  86.         case HAL_PIXEL_FORMAT_RGBX_8888:  
  87.         case HAL_PIXEL_FORMAT_BGRA_8888:  
  88.             bpp = 4;  
  89.             break;  
  90.         case HAL_PIXEL_FORMAT_RGB_888:  
  91.             bpp = 3;  
  92.             break;  
  93.         case HAL_PIXEL_FORMAT_RGB_565:  
  94.         case HAL_PIXEL_FORMAT_RGBA_5551:  
  95.         case HAL_PIXEL_FORMAT_RGBA_4444:  
  96.             bpp = 2;  
  97.             break;  
  98.         default:  
  99.             return -EINVAL;  
  100.     }  
  101.     size_t bpr = (w*bpp + (align-1)) & ~(align-1);  
  102.     size = bpr * h;  
  103.     stride = bpr / bpp;  
  104.   
  105.     int err;  
  106.     if (usage & GRALLOC_USAGE_HW_FB) {  
  107.         err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);  /* 在系统帧缓冲中分配图形缓冲区 */  
  108.     } else {  
  109.         err = gralloc_alloc_buffer(dev, size, usage, pHandle);       /* 在内存中分配图形缓冲区 */  
  110.     }  
  111.   
  112.     if (err < 0) {  
  113.         return err;  
  114.     }  
  115.   
  116.     *pStride = stride;  
  117.     return 0;  
  118. }</span>  
3、gpu_alloc 模块
gpu0内存即非HW_FB内存使用ION分配器进行分配,此文不做详述。
 
4、fb 模块

在 gralloc_device_open 中会根据传递的参数分别初始化两个设备,定义如下:

[cpp] view plaincopy
  1. <span style="font-size:12px;">#define GRALLOC_HARDWARE_FB0 "fb0"  
  2. #define GRALLOC_HARDWARE_GPU0 "gpu0"</span>  
如果参数不是 "gpu0" ,那么是"fb%u"的形式,则会调用fb_device_open 初始化 fb 设备,主要流程和打开 gralloc 基本一致,在函数中会通过调用 mapFrameBuffer->mapFrameBufferLocked 获取帧缓存设备的参数并将其设备节点映射到用户空间,流程如下(大致如此,msm8960平台代码有所变化,msm平台上fb设备文件名是/dev/graphics/fb%u):
[cpp] view plaincopy
  1. <span style="font-size:12px;">int mapFrameBufferLocked(struct private_module_t* module)  
  2. {  
  3.     if (module->framebuffer) {  
  4.         return 0;  
  5.     }  
  6.           
  7.     char const * const device_template[] = {  
  8.             "/dev/graphics/fb%u",  
  9.             "/dev/fb%u",  
  10.             0 };  
  11.   
  12.     int fd = -1;  
  13.     int i=0;  
  14.     char name[64];  
  15.   
  16.     while ((fd==-1) && device_template[i]) {  
  17.         snprintf(name, 64, device_template[i], 0);  
  18.         fd = open(name, O_RDWR, 0);  
  19.         i++;  
  20.     }  
  21.     if (fd < 0)  
  22.         return -errno;  
  23.   
  24.     struct fb_fix_screeninfo finfo;  
  25.     if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)  /* 获取帧缓冲的固定参数 */  
  26.         return -errno;  
  27.   
  28.     struct fb_var_screeninfo info;  
  29.     if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)   /* 获取帧缓冲的可变参数 */  
  30.         return -errno;  
  31.   
  32.     info.reserved[0] = 0;  
  33.     info.reserved[1] = 0;  
  34.     info.reserved[2] = 0;  
  35.     info.xoffset = 0;  
  36.     info.yoffset = 0;  
  37.     info.activate = FB_ACTIVATE_NOW;  
  38.   
  39.     info.bits_per_pixel = 32;  
  40.     info.red.offset     = 16;  
  41.     info.red.length     = 8;  
  42.     info.green.offset   = 8;  
  43.     info.green.length   = 8;  
  44.     info.blue.offset    = 0;  
  45.     info.blue.length    = 8;  
  46.     info.transp.offset  = 24;  
  47.     info.transp.length  = 8;  
  48.   
  49.     /* 
  50.      * Request NUM_BUFFERS screens (at lest 2 for page flipping) 
  51.      */  
  52.     info.yres_virtual = info.yres * NUM_BUFFERS;  /* 帧缓冲总长度 */  
  53.   
  54.   
  55.     uint32_t flags = PAGE_FLIP;  /* 支持缓冲交换 */  
  56.     if (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {  
  57.         info.yres_virtual = info.yres;  
  58.         flags &= ~PAGE_FLIP;  
  59.         LOGW("FBIOPAN_DISPLAY failed, page flipping not supported");  
  60.     }  
  61.   
  62.     if (info.yres_virtual < info.yres * 2) {  
  63.         /* we need at least 2 for page-flipping */  
  64.         info.yres_virtual = info.yres;  
  65.         flags &= ~PAGE_FLIP;  
  66.         LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",  
  67.                 info.yres_virtual, info.yres*2);  
  68.     }  
  69.   
  70.     if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)  
  71.         return -errno;  
  72.   
  73.     int refreshRate = 1000000000000000LLU /  
  74.     (  
  75.             uint64_t( info.upper_margin + info.lower_margin + info.yres )  
  76.             * ( info.left_margin  + info.right_margin + info.xres )  
  77.             * info.pixclock  
  78.     );  /* 计算lcd刷新率 */  
  79.   
  80.     if (refreshRate == 0) {  
  81.         /* bleagh, bad info from the driver */  
  82.         refreshRate = 60*1000;  // 60 Hz  
  83.     }  
  84.   
  85.     if (int(info.width) <= 0 || int(info.height) <= 0) {  
  86.         /* the driver doesn't return that information, default to 160 dpi */  
  87.         info.width  = ((info.xres * 25.4f)/160.0f + 0.5f);  
  88.         info.height = ((info.yres * 25.4f)/160.0f + 0.5f);  
  89.     }  
  90.   
  91.     float xdpi = (info.xres * 25.4f) / info.width;  
  92.     float ydpi = (info.yres * 25.4f) / info.height;  
  93.     float fps  = refreshRate / 1000.0f;  
  94.   
  95.     LOGI(   "using (fd=%d)\n"  
  96.             "id           = %s\n"  
  97.             "xres         = %d px\n"  
  98.             "yres         = %d px\n"  
  99.             "xres_virtual = %d px\n"  
  100.             "yres_virtual = %d px\n"  
  101.             "bpp          = %d\n"  
  102.             "r            = %2u:%u\n"  
  103.             "g            = %2u:%u\n"  
  104.             "b            = %2u:%u\n",  
  105.             fd,  
  106.             finfo.id,  
  107.             info.xres,  
  108.             info.yres,  
  109.             info.xres_virtual,  
  110.             info.yres_virtual,  
  111.             info.bits_per_pixel,  
  112.             info.red.offset, info.red.length,  
  113.             info.green.offset, info.green.length,  
  114.             info.blue.offset, info.blue.length  
  115.     );  
  116.   
  117.     LOGI(   "width        = %d mm (%f dpi)\n"  
  118.             "height       = %d mm (%f dpi)\n"  
  119.             "refresh rate = %.2f Hz\n",  
  120.             info.width,  xdpi,  
  121.             info.height, ydpi,  
  122.             fps  
  123.     );  
  124.   
  125.     if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)  
  126.         return -errno;  
  127.   
  128.     if (finfo.smem_len <= 0)  
  129.         return -errno;  
  130.   
  131.     module->flags = flags;  
  132.     module->info = info;  
  133.     module->finfo = finfo;  
  134.     module->xdpi = xdpi;  
  135.     module->ydpi = ydpi;  
  136.     module->fps = fps;  
  137.   
  138.     /* 
  139.      * map the framebuffer 
  140.      */  
  141.   
  142.     int err;  
  143.     size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);  /* 帧缓冲大小 */  
  144.     module->framebuffer = new private_handle_t(dup(fd), fbSize,  
  145.             private_handle_t::PRIV_FLAGS_USES_PMEM);  
  146.   
  147.     module->numBuffers = info.yres_virtual / info.yres;  /* 计算系统帧缓冲的个数 */  
  148.     module->bufferMask = 0;  
  149.   
  150.     void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);    /* 将fb映射到用户空间 */  
  151.     if (vaddr == MAP_FAILED) {  
  152.         LOGE("Error mapping the framebuffer (%s)", strerror(errno));  
  153.         return -errno;  
  154.     }  
  155.     module->framebuffer->base = intptr_t(vaddr);         /* 帧缓冲的起始虚拟地址 */  
  156.     memset(vaddr, 0, fbSize);  
  157.     return 0;  
  158. }</span>  

关于fb设备的打开和HW_FB内存的分配,是在FrameBufferNativeWindow的构造代码中,可以看到打开fb0设备获取Framebuffer Info,然后使用gralloc为该FrameBufferNativeWindow分配两个HW_FB内存即Framebuffer,即每个Window,double buffer。代码如下:

[cpp] view plaincopy
  1. <span style="font-size:12px;">62/* 
  2. 63 * This implements the (main) framebuffer management. This class is used 
  3. 64 * mostly by SurfaceFlinger, but also by command line GL application. 
  4. 65 * 
  5. 66 * In fact this is an implementation of ANativeWindow on top of 
  6. 67 * the framebuffer. 
  7. 68 * 
  8. 69 * Currently it is pretty simple, it manages only two buffers (the front and 
  9. 70 * back buffer). 
  10. 71 * 
  11. 72 */  
  12. 73  
  13. 74FramebufferNativeWindow::FramebufferNativeWindow()  
  14. 75    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)  
  15. 76{  
  16. 77    hw_module_t const* module;  
  17. 78    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {  
  18. 79        int stride;  
  19. 80        int err;  
  20. 81        int i;  
  21. 82        err = framebuffer_open(module, &fbDev);  
  22. 83        ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));  
  23. 84  
  24. 85        err = gralloc_open(module, &grDev);  
  25. 86        ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));  
  26. 87  
  27. 88        // bail out if we can't initialize the modules  
  28. 89        if (!fbDev || !grDev)  
  29. 90            return;  
  30. 91  
  31. 92        mUpdateOnDemand = (fbDev->setUpdateRect != 0);  
  32. 93  
  33. 94        // initialize the buffer FIFO  
  34. 95        if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&  
  35. 96           fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){  
  36. 97            mNumBuffers = fbDev->numFramebuffers;  
  37. 98        } else {  
  38. 99            mNumBuffers = MIN_NUM_FRAME_BUFFERS;  
  39. 100        }  
  40. 101        mNumFreeBuffers = mNumBuffers;  
  41. 102        mBufferHead = mNumBuffers-1;  
  42. 103  
  43. 104        /* 
  44. 105         * This does not actually change the framebuffer format. It merely 
  45. 106         * fakes this format to surfaceflinger so that when it creates 
  46. 107         * framebuffer surfaces it will use this format. It's really a giant 
  47. 108         * HACK to allow interworking with buggy gralloc+GPU driver 
  48. 109         * implementations. You should *NEVER* need to set this for shipping 
  49. 110         * devices. 
  50. 111         */  
  51. 112#ifdef FRAMEBUFFER_FORCE_FORMAT  
  52. 113        *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;  
  53. 114#endif  
  54. 115  
  55. 116        for (i = 0; i < mNumBuffers; i++)  
  56. 117        {  
  57. 118                buffers[i] = new NativeBuffer(  
  58. 119                        fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);  
  59. 120        }  
  60. 121  
  61. 122        for (i = 0; i < mNumBuffers; i++)  
  62. 123        {  
  63. 124                err = grDev->alloc(grDev,  
  64. 125                        fbDev->width, fbDev->height, fbDev->format,  
  65. 126                        GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);  
  66. 127  
  67. 128                ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",  
  68. 129                        i, fbDev->width, fbDev->height, strerror(-err));  
  69. 130  
  70. 131                if (err)  
  71. 132                {  
  72. 133                        mNumBuffers = i;  
  73. 134                        mNumFreeBuffers = i;  
  74. 135                        mBufferHead = mNumBuffers-1;  
  75. 136                        break;  
  76. 137                }  
  77. 138        }  
  78. 139  
  79. 140        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;  
  80. 141        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;  
  81. 142        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;  
  82. 143        const_cast<int&>(ANativeWindow::minSwapInterval) =  
  83. 144            fbDev->minSwapInterval;  
  84. 145        const_cast<int&>(ANativeWindow::maxSwapInterval) =  
  85. 146            fbDev->maxSwapInterval;  
  86. 147    } else {  
  87. 148        ALOGE("Couldn't get gralloc module");  
  88. 149    }  
  89. 150  
  90. 151    ANativeWindow::setSwapInterval = setSwapInterval;  
  91. 152    ANativeWindow::dequeueBuffer = dequeueBuffer;  
  92. 153    ANativeWindow::lockBuffer = lockBuffer;  
  93. 154    ANativeWindow::queueBuffer = queueBuffer;  
  94. 155    ANativeWindow::query = query;  
  95. 156    ANativeWindow::perform = perform;  
  96. 157    ANativeWindow::cancelBuffer = NULL;  
  97. 158}</span>  


创建FrameBufferNativeWindow仅发生在DisplayHardware的构造后初始化中,代码片段如下:

[cpp] view plaincopy
  1. 150void DisplayHardware::init(uint32_t dpy)  
  2. 151{  
  3. 152    mNativeWindow = new FramebufferNativeWindow();  //******  
  4. 153    framebuffer_device_t const * fbDev = mNativeWindow->getDevice();  
  5. 154    if (!fbDev) {  
  6. 155        ALOGE("Display subsystem failed to initialize. check logs. exiting...");  
  7. 156        exit(0);  
  8. 157    }  
  9. 158  
  10. 159    int format;  
  11. 160    ANativeWindow const * const window = mNativeWindow.get();  
  12. 161    window->query(window, NATIVE_WINDOW_FORMAT, &format);  
  13. 162    mDpiX = mNativeWindow->xdpi;  
  14. 163    mDpiY = mNativeWindow->ydpi;  
  15. 164    mRefreshRate = fbDev->fps;  
  16. ....  
  17. }  


而DisplayHardware的真正构造仅在Surfacelinger启动后readyToRun中,其余都是使用拷贝构造默认的Bitwise Copy,当然这仅仅是针对一块屏的情况,当前大屏主流。相关代码片段如下:

[cpp] view plaincopy
  1. 217status_t SurfaceFlinger::readyToRun()  
  2. 218{  
  3. 219    ALOGI(   "SurfaceFlinger's main thread ready to run. "  
  4. 220            "Initializing graphics H/W...");  
  5. 221  
  6. 222    // we only support one display currently  
  7. 223    int dpy = 0;  
  8. 224  
  9. 225    {  
  10. 226        // initialize the main display  
  11. 227        GraphicPlane& plane(graphicPlane(dpy));  
  12. 228        DisplayHardware* const hw = new DisplayHardware(this, dpy); //*******  
  13. 229        plane.setDisplayHardware(hw);  
  14. 230    }  
  15. 231  
  16. 232    // create the shared control-block  
  17. 233    mServerHeap = new MemoryHeapBase(4096,  
  18. 234            MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");  
  19. 235    ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");  
  20. 236  
  21. 237    mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());  
  22. 238    ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");  
  23. 239  
  24. 240    new(mServerCblk) surface_flinger_cblk_t;  
  25. 241  
  26. 242    // initialize primary screen  
  27. 243    // (other display should be initialized in the same manner, but  
  28. 244    // asynchronously, as they could come and go. None of this is supported  
  29. 245    // yet).  
  30. 246    const GraphicPlane& plane(graphicPlane(dpy));  
  31. 247    const DisplayHardware& hw = plane.displayHardware();  
  32. 248    const uint32_t w = hw.getWidth();  
  33. 249    const uint32_t h = hw.getHeight();  
  34. 250    const uint32_t f = hw.getFormat();  
  35. 251    hw.makeCurrent();  
  36. .....  
  37. }  

 

fb 模块最重要的工作就是将应用程序指定的内容写入显存中,是通过函数 fb_post完成的,流程如下(msm8960代码大致如此,不过使用的是FBIOPUT_VSCREENINFO IOCTL_CODE):

[cpp] view plaincopy
  1. <span style="font-size:12px;">/* 将图形缓冲区buffer的内容渲染到帧缓冲区中去 */  
  2. static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)  
  3. {  
  4.     unsigned int phys;  
  5.     void* virt;  
  6.     int pitch;  
  7.     int format;  
  8.   
  9.     /* 首先验证参数handle指向的一块图形缓冲区的确是由Gralloc模块分配的 */  
  10.     if (private_handle_t::validate(buffer) < 0)  
  11.         return -EINVAL;  
  12.   
  13.     fb_context_t* ctx = (fb_context_t*)dev;  
  14.   
  15.     private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);  /* 图形缓冲区 */  
  16.     private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);    /* 帧缓冲区 */  
  17.   
  18.     if (m->currentBuffer) {  /* 当前正在渲染的图形缓冲区 */  
  19.         m->base.unlock(&m->base, m->currentBuffer);  
  20.         m->currentBuffer = 0;  
  21.     }  
  22.   
  23.     if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {  /* 如果图形缓冲区是在系统帧缓冲中分配的 */  
  24.         m->base.lock(&m->base, buffer,  /* 锁定图像缓冲区 */  
  25.                 private_module_t::PRIV_USAGE_LOCKED_FOR_POST,  
  26.                 0, 0, m->info.xres, m->info.yres, NULL);  
  27.   
  28.         const size_t offset = hnd->base - m->framebuffer->base; /* 计算图形缓冲区与帧缓冲的偏移 */  
  29.         /* 将作为参数的fb_var_screeninfo结构体的成员变量activate的值设置FB_ACTIVATE_VBL 
  30.          * 表示要等到下一个垂直同步事件出现时,再将当前要渲染的图形缓冲区的内容绘制出来 
  31.          * 这样做的目的是避免出现屏幕闪烁,即避免前后两个图形缓冲区的内容各有一部分同时出现屏幕中 */  
  32.         m->info.activate = FB_ACTIVATE_VBL;  
  33.         m->info.yoffset = offset / m->finfo.line_length;  /* 得到偏移的起始行 */  
  34.   
  35.         if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) == -1) {  /* 刷新显示内容 */  
  36.             LOGE("FBIOPAN_DISPLAY failed");  
  37.             m->base.unlock(&m->base, buffer);   
  38.             return -errno;  
  39.         }  
  40.   
  41.         if (UNLIKELY(mDebugFps)) {  
  42.             debugShowFPS();  
  43.         }  
  44.   
  45.         m->currentBuffer = buffer;  /* 设置当前图形缓冲区 */  
  46.     return 0;  
  47. }</span>  

5、Gralloc map/unmap、register/unregister

当GPU内存file descriptor从一个进程A传递到另一个进程B后,进程B做gralloc_register_buffer就是使用allocator此时是ION将该buffer在本进程映射一下,用于访问。这些功能做为gralloc的mapper功能。

关于内存file descriptor、binder传递该内存fd的具体机制参见ION的功能。


原创粉丝点击