您的位置:首页 > 产品设计 > UI/UE

GUI系统之SurfaceFlinger(2)Gralloc与Framebuffer

2013-05-21 11:56 441 查看
文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正
转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/

1.1 Gralloc与Framebuffer

相信做过Linux开发的人对framebuffer不会太陌生,它是内核系统提供的一个与硬件无关的显示抽象层。之所以称之为buffer,是由于它也是系统存储空间的一部分,是一块包含屏幕显示信息的缓冲区。由此可见,在“一切都是文件”的Linux系统中,Framebuffer被看成了终端monitor的“化身”。它借助于文件系统向上层提供统一而方便的操作接口,从而让用户空间程序可以不用修改就能适应多种屏幕——无论这些屏幕是哪家厂商、什么型号,都由framebuffer内部来兼容。
在Android系统中,framebuffer提供的设备文件节点是/dev/graphics/fb*。因为理论上支持多个屏幕显示,所以fb按数字序号进行排列,即fb0、fb1等等。其中第一个fb0是主显示屏幕,必须存在。如下是某设备的fb设备截图:


图 11‑2 fb节点
 
根据前面章节学习过的知识,Android中各子系统通常不会直接基于Linux驱动来实现,而是由HAL层间接引用底层架构,在显示系统中也同样如此——它借助于HAL层来操作帧缓冲区,而完成这一中介任务的就是Gralloc,下面我们分几个方面来介绍。
<1>  Gralloc的加载
Gralloc对应的模块是由FramebufferNativeWindow(OpenGLES的本地窗口之一,后面小节有详细介绍)在构造时加载的,即:
hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
这个hw_get_module函数我们在前面已经见过很多次了,它是上层加载HAL库的入口,这里传入的模块ID名为:
#define GRALLOC_HARDWARE_MODULE_ID  "gralloc"
按照hw_get_module的作法,它会在如下路径中查找与ID值匹配的库:
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
lib库名有如下几种形式:
    gralloc.[ro.hardware].so
    gralloc.[ro.product.board].so
    gralloc.[ro.board.platform].so
    gralloc.[ro.arch].so
或者当上述的系统属性组成的文件名都不存在时,就使用默认的:
    gralloc.default.so
最后这个库是Android原生态的实现,位置在hardware/libhardware/modules/gralloc/中,它由gralloc.cpp、framebuffer.cpp和mapper.cpp三个主要源文件编译生成。
 
<2>  Gralloc提供的接口
Gralloc对应的库被加载后,我们来看下它都提供了哪些接口方法。
由于Gralloc代表的是一个hw_module_t,这是HAL中统一定义的硬件模块描述体,所以和其它module所能提供的接口是完全一致的:
/*hardware/libhardware/include/hardware/Hardware.h*/
typedef struct hw_module_t {…
    structhw_module_methods_t* methods;
                …
} hw_module_t;
 
typedef struct hw_module_methods_t {
    int (*open)(const structhw_module_t* module, const char* id,
            structhw_device_t** device);
} hw_module_methods_t;
这个open接口可以帮助上层打开两个设备,分别是:
       #defineGRALLOC_HARDWARE_FB0   "fb0"
以及   #define GRALLOC_HARDWARE_GPU0  "gpu0"
 
“fb0”就是我们前面说的主屏幕,gpu0负责图形缓冲区的分配和释放。这两个设备将由FramebufferNativeWindow中的fbDev和grDev成员变量来管理。
/*frameworks/native/libs/ui/FramebufferNativeWindow.cpp*/      
FramebufferNativeWindow::FramebufferNativeWindow()
            : BASE(),fbDev(0), grDev(0), mUpdateOnDemand(false)
{…
    err = framebuffer_open(module, &fbDev);
    err =gralloc_open(module, &grDev);
这两个open函数分别是由hardware/libhardware/include/hardware目录下的Fb.h和Gralloc.h头文件提供的打开fb及gralloc设备的便捷实现。其中fb对应的设备名为GRALLOC_HARDWARE_FB0,gralloc则是GRALLOC_HARDWARE_GPU0。各硬件生产商可以根据自己的平台配置来实现fb和gralloc的打开、关闭以及管理,比如hardware/msm7k/libgralloc就是一个很好的参考例子。
原生态的实现在hardware/libhardware/modules/gralloc中,对应的是gralloc_device_open@Gralloc.cpp。在这个函数中,根据设备名来判断是打开fb或者gralloc。
/*hardware/libhardware/modules/gralloc/Gralloc.cpp*/
int gralloc_device_open(const hw_module_t* module, const char* name,hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {//打开gralloc设备
        …
    } else {
        status = fb_device_open(module, name, device);//否则就是fb设备
    }
    return status;
}
先来大概看下framebuffer设备的打开过程:
/*hardware/libhardware/modules/gralloc/Framebuffer.cpp*/
int fb_device_open(hw_module_t const* module, const char* name,hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name,GRALLOC_HARDWARE_FB0)) {//设备名是否正确
        fb_context_t *dev =(fb_context_t*)malloc(sizeof(*dev));//分配hw_device_t空间,这是一个“壳”
        memset(dev, 0,sizeof(*dev));//初始化,良好的编程习惯
                   …
       dev->device.common.close = fb_close;//这几个接口是fb设备的核心
       dev->device.setSwapInterval = fb_setSwapInterval;
        dev->device.post          = fb_post;
                   …
        private_module_t* m =(private_module_t*)module;
        status = mapFrameBuffer(m);//内存映射,以及参数配置
        if (status >= 0) {
            …
            *device =&dev->device.common;//“壳”和“核心”的关系
        }
    }
    return status;
}
其中fb_context_t是framebuffer内部使用的一个类,它包含了众多信息,而最终返回的device只是其内部的device.common。这种“通用和差异”并存的编码风格在HAL层非常常见,大家要做到习以为常。
Struct类型fb_context_t里的唯一成员就是framebuffer_device_t,这是对frambuffer设备的统一描述。一个标准的fb设备通常要提供如下的函数实现:
Ø  int(*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
将buffer数据post到显示屏上。要求buffer必须与屏幕尺寸一致,并且没有被locked。这样的话buffer内容将在下一次VSYNC中被显示出来
Ø  int(*setSwapInterval)(struct framebuffer_device_t* window, int interval);
设置两个缓冲区交换的时间间隔
Ø  int(*setUpdateRect)(struct framebuffer_device_t* window, int left, int top,
                 int width, int height);
设置刷新区域,需要framebuffer驱动支持“update-on-demand”。也就是说在这个区域外的数据很可能被认为无效
 
我们再来解释下framebuffer_device_t中一些重要的成员变量,如下表:
表格 11‑1 framebuffer_device_t中的重要成员变量
变量描述
uint32_t  flags
标志位,指示framebuffer的属性配置
uint32_t  width;
uint32_t  height;
framebuffer的宽和高,以像素为单位
int       format
framebuffer的像素格式,比如:HAL_PIXEL_FORMAT_RGBA_8888 HAL_PIXEL_FORMAT_RGBX_8888
HAL_PIXEL_FORMAT_RGB_888
HAL_PIXEL_FORMAT_RGB_565等等
float     xdpi;
float     ydpi;
x和y轴的密度(pixel per inch)
float     fps
屏幕的每秒刷新频率,假如无法正常从设备获取的话,默认设置为60Hz
int       minSwapInterval;
int       maxSwapInterval;
该framebuffer支持的最小和最大缓冲交换时间
 
到目前为止,我们还没看到系统是如何打开具体的fb设备、以及如何对fb进行配置,这些工作都是在mapFrameBuffer()完成的。这个函数首先尝试打开(调用open,权限为O_RDWR)如下路径中的fb设备:
"/dev/graphics/fb%u"或者 "/dev/fb%u",其中%u当前的实现中只用了“0”,也就是只会打开一个fb,虽然Android从趋势上看是要支持多屏幕的。成功打开fb后,我们通过:
ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
ioctl(fd, FBIOGET_VSCREENINFO, &info)
来得到显示屏的一系列参数,同时通过
ioctl(fd, FBIOPUT_VSCREENINFO, &info)来对底层fb进行配置。
这个函数的另一重要任务,就是对fb做内存映射,主要语句如下:
    void* vaddr = mmap(0,fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);   
   module->framebuffer->base = intptr_t(vaddr);
    memset(vaddr, 0, fbSize);
所以映射地址是module->framebuffer->base,这个module对应的是前面hw_get_module(GRALLOC_HARDWARE_MODULE_ID,&module)得到的hw_module_t(被强制类型转化为private_module_t,大家可以自己看下这个struct)。
 
接下来再看下对gralloc设备的打开操作,它相对fb简单些,如下所示:
/*hardware/libhardware/modules/gralloc/Gralloc.cpp*/
int gralloc_device_open(const hw_module_t* module, const char* name,hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name,GRALLOC_HARDWARE_GPU0)) {
        gralloc_context_t*dev;//做法和fb类似
        dev =(gralloc_context_t*)malloc(sizeof(*dev));//分配空间
        /* initialize ourstate here */
        memset(dev, 0,sizeof(*dev));
                   …
       dev->device.alloc   =gralloc_alloc; //从提供的接口来看,gralloc和分配/释放有关系
       dev->device.free    =gralloc_free;

}
与fb相似的部分我们就不多做介绍了。因为gralloc担负着图形缓冲区的分配与释放,所以它提供了两个最重要的实现即alloc和free。这里我们先不深入分析了,只要知道gralloc所提供的功能就可以了。我们以下面简图来小结对Gralloc的分析。


图 11‑3 Gralloc简图
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: