hw_get_module_by_class:hw get module 失败name gralloc错误,什么原因

Android系统(21)
功能:Galloc模块是显示框架的硬件抽象层,主要是封装了/dev/graphics/fb%d设备文件的操作,
为框架层提供接口。
实现:Gralloc是HAl中的模块,会被编译成动态链接库。框架层会将动态链接库加载到内存中,
并利用导出符号得到封装的方法。
问题: Gralloc模块如何加载使用、Gralloc做了哪些事、Gralloc模块内部结构?
Gralloc模块如何加载、使用
答:框架层利用hw_get_module查找模块,并获取导出符号HMI对应的结构体。
hw_get_module(id, module) 提供给框架层调用
int hw_get_module(const char *id, const struct hw_module_t **module)
return hw_get_module_by_class(id, NULL, module);
hw_get_module直接调用了hw_get_module_by_class
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module)
for (i=0 ; i&HAL_VARIANT_KEYS_COUNT+1 ; i++) {
if (i & HAL_VARIANT_KEYS_COUNT) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
//1.在/system/lib/hw/和/vendor/lib/hw/目录下查找四个指定名称的gralloc.xx.so
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH2, name, prop);
if (access(path, R_OK) == 0)
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH1, name, prop);
if (access(path, R_OK) == 0)
//2.没有指定gralloc.xx.so时,使用 /system/lib/hw/gralloc.default.so
snprintf(path, sizeof(path), "%s/%s.default.so",
HAL_LIBRARY_PATH1, name);
if (access(path, R_OK) == 0)
status = -ENOENT;
if (i & HAL_VARIANT_KEYS_COUNT+1) {
//3.加载gralloc.xx.so到内存
status = load(class_id, path, module);
函数很简单,在几个路径下查询gralloc.xx.so模块选用一个,最后利用load函数将其加载到内存
static int load(const char *id,
const char *path,
const struct hw_module_t **pHmi)
//1.使用dlopen打开动态链接库
handle = dlopen(path, RTLD_NOW);
//2.获取动态链接库符号HMI对应地址,得到结构体hw_module_t
(HAL_MODULE_INFO_SYM_AS_STR是一个常量"HMI",也就是HAL中所有动态链接库导出的都是HMI符号)
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym);
hmi-&dso =
//3.返回给调用者hw_module_t
由此分析可知,load函数关键操作是获取.so中的HMI符号对应地址,得到hw_module_t,而hw_module_t是模块对所有设备操作的封装。
实际上HMI对应的是下面的结构:hardware/libhardware/modules/gralloc/gralloc.cpp
struct private_module_t HAL_MODULE_INFO_SYM = {
它与hw_module_t的关系为:
继承关系:private_module_t继承自gralloc_module_t继承自hw_module_t,因此private_module_t指针可以转化为hw_module_t指针。
Gralloc做了哪些事
答:封装了一个模块两个设备,提供了映射、分配、渲染的三个主要功能。
从APP层到驱动层,图像显示的过程:
应用程序首选需要分配一个图像缓冲区并使用它,但是有由于app在java虚拟机运行中而图形缓冲区分配是在本地代码实现的,因此需要一个映射的过程将图像缓冲区映射到应用的地址空间中,这样应用程序就可以使用图形缓冲区了;而要让图形显示到LCD中,需要把数据写入设备文件里,这里还需要一个渲染的过程用于将图像缓冲区的数据送到帧缓冲区中。
由上面的分析可知,HAL层需要提供的抽象操作包括:分配、映射、渲染。而Gralloc模块中将这些操作封装到了下面的结构中。
1.加载Gralloc模块
打开gralloc设备
打开fb设备
2.分配图形缓冲区 (gralloc设备)
3.图形缓冲区映射 (Gralloc模块)
4.渲染图形缓冲区 (fb设备)
Gralloc模块内部结构
答:从功能角度来分析结构更容易。
忽略掉继承封装这些细节,下面画出了Gralloc模块的内部结构,这样再分析代码就很清晰了
galloc设备的方式实现在gralloc.cpp中, fb设备的方法实现在framebuffer.cpp中, 映射的方法实现在mapper.cpp中
Gralloc结构体分析
private_module_t定义在文件hardware/libhardware/modules/gralloc/gralloc_priv.h
主要用来描述帧缓冲区信息。其中private_handle_t继承自native_handle,用来描述一块图形缓冲区,它可能是在内存中分配的,也可能是在帧缓冲区中分配的,视具体情况而定。
struct private_module_t {
gralloc_module_
private_handle_t*
//指向帧缓冲区的句柄
//是否支持双缓冲
uint32_t numB
//图形缓冲区的个数
uint32_t bufferM
//图形缓冲区的使用情况
pthread_mutex_
buffer_handle_t currentB
//正在被使用的缓冲区
native_handle* buffer_handle_t;
void* pmem_master_
struct fb_var_
struct fb_fix_
};gralloc_module_t定义在文件hardware/libhardware/include/hardware/gralloc.h
registerBuffer用来注册缓冲区,lock用来锁定。这里的注册实际上也就是映射地址空间的功能。
typedef struct gralloc_module_t {
int (*registerBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);
int (*unregisterBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);
int (*lock)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
int (*unlock)(struct gralloc_module_t const* module,
buffer_handle_t handle);
}alloc_device_t 也是定义在文件hardware/libhardware/include/hardware/gralloc.h
结构体用来描述一个Gralloc设备,主要负责分配和释放图形缓冲区。
typedef struct alloc_device_t {
struct hw_device_
int (*alloc)(struct alloc_device_t* dev,
int w, int h, int format, int usage,
buffer_handle_t* handle, int* stride);
int (*free)(struct alloc_device_t* dev,
buffer_handle_t handle);
} alloc_device_t;
framebuffer_device_t 定义在文件hardware/libhardware/include/hardware/gralloc.h
结构体用来描述一个fb设备,即帧缓冲区的信息。setSwapInterval用来描述帧缓冲区与前后两个图形缓冲区交换的时间;setUpdateRect用来设置更新的区域;post用来将图形缓冲区渲染到帧缓冲区中区。
typedef struct framebuffer_device_t {
struct hw_device_
/* flags describing some attributes of the framebuffer */
const uint32_
/* dimensions of the framebuffer in pixels */
const uint32_
const uint32_
/* frambuffer stride in pixels */
/* framebuffer pixel format */
/* resolution of the framebuffer's display panel in pixel per inch*/
/* framebuffer's display panel refresh rate in frames per second */
/* min swap interval supported by this framebuffer */
/* max swap interval supported by this framebuffer */
int reserved[8];
int (*setSwapInterval)(struct framebuffer_device_t* window,
int interval);
int (*setUpdateRect)(struct framebuffer_device_t* window,
int left, int top, int width, int height);
int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
int (*compositionComplete)(struct framebuffer_device_t* dev);
void* reserved_proc[8];
} framebuffer_device_t;
Gralloc函数分析
gralloc_device_open定义在文件hardware/libhardware/modules/gralloc/gralloc.cpp
这里使用hw_module_t方法中的open操作打开并返回了alloc_device_t设备
struct gralloc_context_t {
alloc_device_
/* our private data here */
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 = (gralloc_context_t*)malloc(sizeof(*dev));
/* initialize our state here */
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev-&device.common.tag = HARDWARE_DEVICE_TAG;
dev-&device.common.version = 0;
dev-&device.common.module = const_cast&hw_module_t*&(module);
dev-&device.common.close = gralloc_
dev-&device.alloc
= gralloc_
dev-&device.free
= gralloc_
*device = &dev-&device.
status = 0;
}fb_device_open定义在文件hardware/libhardware/modules/gralloc/framebuffer.cpp
函数打开并返回了setSwapInterval、post、setUpdateRect操作
struct fb_context_t {
framebuffer_device_
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)) {
alloc_device_t* gralloc_
status = gralloc_open(module, &gralloc_device);
if (status & 0)
/* initialize our state here */
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev-&device.common.tag = HARDWARE_DEVICE_TAG;
dev-&device.common.version = 0;
dev-&device.common.module = const_cast&hw_module_t*&(module);
dev-&device.common.close = fb_
dev-&device.setSwapInterval = fb_setSwapI
dev-&device.post
dev-&device.setUpdateRect = 0;
private_module_t* m = (private_module_t*)
status = mapFrameBuffer(m);
if (status &= 0) {
int stride = m-&finfo.line_length / (m-&info.bits_per_pixel && 3);
int format = (m-&info.bits_per_pixel == 32)
? HAL_PIXEL_FORMAT_RGBX_8888
: HAL_PIXEL_FORMAT_RGB_565;
#ifdef NO_32BPP
format = HAL_PIXEL_FORMAT_RGB_565;
const_cast&uint32_t&&(dev-&device.flags) = 0;
const_cast&uint32_t&&(dev-&device.width) = m-&info.
const_cast&uint32_t&&(dev-&device.height) = m-&info.
const_cast&int&&(dev-&device.stride) =
const_cast&int&&(dev-&device.format) =
const_cast&float&&(dev-&device.xdpi) = m-&
const_cast&float&&(dev-&device.ydpi) = m-&
const_cast&float&&(dev-&device.fps) = m-&
const_cast&int&&(dev-&device.minSwapInterval) = 1;
const_cast&int&&(dev-&device.maxSwapInterval) = 1;
*device = &dev-&device.
Gralloc总结
上面从功能的角度来学习Gralloc,发现它很简单,就是实现了图形缓冲区的分配与映射、帧缓冲区的渲染,总结起来就是分配、映射、渲染。而这些工作分别封装到了gralloc_module_t、alloc_device_t、framebuffer_device_t当中,经过封装继承的关系组织起来。其中gralloc_module_t在hw_get_module被调用时就返回给了框架层,而alloc_device_t和alloc_device_t在hw_module_t-&method-&open方法被调用时返回给了框架层。这里的结构已经很清楚了。
一些函数和关键技术可以稍作分析,在需要使用时详细分析研究。至此,gralloc从框架上基本愉快的学习完成。Android&gralloc模块接口
从字面就可以看出来Gralloc接口是为了显示内存分配与释放
& Graphics Allocation。它的主要目的有三个:
为应用分配显示用内存;
可以把显示内存在不同进程间进行映射;
不同芯片平台对显存的实现不一样,所以Android只定义了接口,具体实现由各芯片厂商来提供。多数芯片厂商没有把gralloc模块开源,而只是提供了gralloc.xxx.so二进制文件。在Android的源代码里,hardware/libhardware/modules/gralloc有一个参考设计。
显存的分配,共享基于handle,buffer_handle_t。handle的实现可以用另外一个话题来讨论,这里重点是gralloc,就不深究handle了。
gralloc模块加载过程
这个模块既会被SurfaceFlinger进程加载,也会被用户app加载。SurfaceFlinger加载gralloc的目的是为了分配/释放内存,用户app加载这个模块是为了把SurfaceFlinger分配到的内存映射到用户app里。这个可能有点不好理解,SurfaceFlinger和用户app位于不同的进程里,他们怎么能一起分配,映射内存?这个就是Android共享内存的基础,在以后的文章里再细述吧。
在SurfaceFlinger侧,链接的libui.so里有GraphicBufferAllocator。在这个类的构造函数里,他首先动态加载(dlopen)gralloc模块,然后调用gralloc_open就可以取得gralloc的alloc/free函数指针了。
在应用侧,应用链接的libui.so(和SurfaceFlinger同一个库)里有GraphicBufferMapper。这个类的构造函数会动态加载gralloc模块。加载以后就可以调用gralloc的registerBuffer把SurfaceFlinger分配的内存映射到本进程里。
这两个类动态加载gralloc用的函数都是hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
gralloc接口
先简单看看Android对这个接口的定义。这个定义在hardware/libhardware/include/hardware/gralloc.h里。
主要关心的几个函数接口:
typedef struct gralloc_module_t {
(*registerBuffer)(struct gralloc_module_t const* module,
&&&&&&&&&&&
buffer_handle_t handle);
(*unregisterBuffer)(struct gralloc_module_t const*
&&&&&&&&&&&
buffer_handle_t handle);
(*lock)(struct gralloc_module_t const* module,
&&&&&&&&&&&
buffer_handle_t handle, int usage,
&&&&&&&&&&&
int l, int t, int w, int h,
&&&&&&&&&&&
void** vaddr);
(*unlock)(struct gralloc_module_t const* module,
&&&&&&&&&&&
buffer_handle_t handle);
} gralloc_module_t;
typedef struct alloc_device_t {
(*alloc)(struct alloc_device_t* dev,
&&&&&&&&&&&
int w, int h, int format, int usage,
&&&&&&&&&&&
buffer_handle_t* handle, int* stride);
(*free)(struct alloc_device_t* dev,
&&&&&&&&&&&
buffer_handle_t handle);
} alloc_device_t;
这里只列出了几个重要的接口函数。
alloc/free&这两个函数主要用于SurfaceFlinger进程分配/释放显示内存;
registerBuffer&用户app用这个函数把显示内存映射到本进程内;
unregisterBuffer&跟registerBuffer相反,用完以后解除映射;
lock是告诉gralloc应用要访问这个buffer的某个区域(参数l,
t, w, h)了。如果这个平台有cache一致性问题的话在这个函数里应该flush一下cache。
unlock是说访问完毕,有些平台上可能需要flush/invalidate
Gralloc在内核里的实现差异很大。Android提供了ion接口,使得共享内存在不同芯片有了较为类似的基础。对于不同的usage,也可能有不同的内存块供ion/gralloc来使用。内核里ion的实现可以参考ion的源代码。它在drivers/staging/android/ion/路径下。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。51CTO旗下网站
Android GUI系统学习1:Gralloc
Gralloc模块是从Android Eclair(android 2.1)开始加入的一个HAL模块,Gralloc的含义为是Graphics Alloc(图形分配)。他对上为libui提供服务,为其分配显存,刷新显示等。对下对framebuffer进行管理。
作者:HAOMCU来源:| 13:12
Gralloc模块是从Android Eclair(android 2.1)开始加入的一个HAL模块,Gralloc的含义为是Graphics Alloc(图形分配)。他对上为libui提供服务,为其分配显存,刷新显示等。对下对framebuffer进行管理。
gralloc代码通常位于hardware/libhardware/modules/gralloc目录下。包含以下几个文件:
Android.mk &framebuffer.cpp &gralloc.cpp &gralloc_priv.h &gr.h &mapper.cpp
另外,与其相关的头文件位于hardware/libhardware/include/hardware,涉及fb.h和gralloc.h。
下面从gralloc的调用开始学习gralloc的代码。代码基于android4.4。
gralloc的调用是从FramebufferNativeWindow.cpp的构造函数开始的。FramebufferNativeWindow实现FrameBuffer的管理,它主要被SurfaceFlinger使用,也可以被OpenGL Native程序使用。在本质上,它在Framebuffer之上实现了一个ANativeWindow,目前它只管理两个buffers:front and back buffer。
如下所示(FramebufferNativeWindow.cpp):
FramebufferNativeWindow::FramebufferNativeWindow()&&:&BASE(),&fbDev(0),&grDev(0),&mUpdateOnDemand(false)&&{&&hw_module_t&const*&&&if&(hw_get_module(GRALLOC_HARDWARE_MODULE_ID,&&module)&==&0)&{&&int&&&int&&&int&i;&&err&=&framebuffer_open(module,&&fbDev);&&ALOGE_IF(err,&&couldn't&open&framebuffer&HAL&(%s)&,&strerror(-err));&&&err&=&gralloc_open(module,&&grDev);&&ALOGE_IF(err,&&couldn't&open&gralloc&HAL&(%s)&,&strerror(-err));&&&&&if&(!fbDev&||&!grDev)&&return;&&&mUpdateOnDemand&=&(fbDev-&setUpdateRect&!=&0);&&&&&if(fbDev-&numFramebuffers&&=&MIN_NUM_FRAME_BUFFERS&&&&&fbDev-&numFramebuffers&&=&MAX_NUM_FRAME_BUFFERS){&mNumBuffers&=&fbDev-&numF&&}&else&{&&mNumBuffers&=&MIN_NUM_FRAME_BUFFERS;&&}&&mNumFreeBuffers&=&mNumB&&mBufferHead&=&mNumBuffers-1;&&&&&&&&&&&&#ifdef&FRAMEBUFFER_FORCE_FORMAT&&*((uint32_t&*)&fbDev-&format)&=&FRAMEBUFFER_FORCE_FORMAT;&&#endif&&&for&(i&=&0;&i&&&mNumB&i++)&{&buffers[i]&=&new&NativeBuffer(&fbDev-&width,&fbDev-&height,&fbDev-&format,&GRALLOC_USAGE_HW_FB);&&}&&&for&(i&=&0;&i&&&mNumB&i++)&{&err&=&grDev-&alloc(grDev,&&fbDev-&width,&fbDev-&height,&fbDev-&format,&&GRALLOC_USAGE_HW_FB,&&buffers[i]-&handle,&&buffers[i]-&stride);&&&ALOGE_IF(err,&&fb&buffer&%d&allocation&failed&w=%d,&h=%d,&err=%s&,&&i,&fbDev-&width,&fbDev-&height,&strerror(-err));&&&if&(err)&&{&&mNumBuffers&=&i;&&mNumFreeBuffers&=&i;&&mBufferHead&=&mNumBuffers-1;&&break;&&}&&}&&&const_cast&uint32_t&&(ANativeWindow::flags)&=&fbDev-&&&const_cast&float&&(ANativeWindow::xdpi)&=&fbDev-&&&const_cast&float&&(ANativeWindow::ydpi)&=&fbDev-&&&const_cast&int&&(ANativeWindow::minSwapInterval)&=&&fbDev-&minSwapI&&const_cast&int&&(ANativeWindow::maxSwapInterval)&=&&fbDev-&maxSwapI&&}&else&{&&ALOGE(&Couldn't&get&gralloc&module&);&&}&&&ANativeWindow::setSwapInterval&=&setSwapI&&ANativeWindow::dequeueBuffer&=&dequeueB&&ANativeWindow::queueBuffer&=&queueB&&ANativeWindow::query&=&&&ANativeWindow::perform&=&&&&ANativeWindow::dequeueBuffer_DEPRECATED&=&dequeueBuffer_DEPRECATED;&&ANativeWindow::lockBuffer_DEPRECATED&=&lockBuffer_DEPRECATED;&&ANativeWindow::queueBuffer_DEPRECATED&=&queueBuffer_DEPRECATED;&&}&
这里会先根据gralloc的module ID来得到hw_module_t结构。hw_get_module-&hw_get_module_by_class。在hw_get_module_by_class里面,首先根据平台配置找到gralloc动态库的位置,默认使用gralloc.default.so。
参见以下代码(hardware.c):
for&(i=0&;&i&HAL_VARIANT_KEYS_COUNT+1&;&i++)&{&&&&&&&&&if&(i&&&HAL_VARIANT_KEYS_COUNT)&{&&&&&&&&&&&&&if&(property_get(variant_keys[i],&prop,&NULL)&==&0)&{&&&&&&&&&&&&&&&&&continue;&&&&&&&&&&&&&}&&&&&&&&&&&&&snprintf(path,&sizeof(path),&&%s/%s.%s.so&,&&&&&&&&&&&&&&&&&&&&&&HAL_LIBRARY_PATH2,&name,&prop);&&&&&&&&&&&&&if&(access(path,&R_OK)&==&0)&break;&&&&&&&&&&&&&&&snprintf(path,&sizeof(path),&&%s/%s.%s.so&,&&&&&&&&&&&&&&&&&&&&&&HAL_LIBRARY_PATH1,&name,&prop);&&&&&&&&&&&&&if&(access(path,&R_OK)&==&0)&break;&&&&&&&&&}&else&{&&&&&&&&&&&&&snprintf(path,&sizeof(path),&&%s/%s.default.so&,&&&&&&&&&&&&&&&&&&&&&&HAL_LIBRARY_PATH2,&name);&&&&&&&&&&&&&if&(access(path,&R_OK)&==&0)&break;&&&&&&&&&&&&&&&snprintf(path,&sizeof(path),&&%s/%s.default.so&,&&&&&&&&&&&&&&&&&&&&&&HAL_LIBRARY_PATH1,&name);&&&&&&&&&&&&&if&(access(path,&R_OK)&==&0)&break;&&&&&&&&&}&&&&&}&&status&=&-ENOENT;&&if&(i&&&HAL_VARIANT_KEYS_COUNT+1)&{&&&&&status&=&load(class_id,&path,&module);&&}&
找到gralloc库的路径后,会调用load函数,在load函数中使用dlopen打开找到的库,并根据HAL_MODULE_INFO_SYM_AS_STR(其值为HMI)获取到hw_module_t(即HAL_MODULE_INFO_SYM)结构体指针,以及把dlopen返回的handle保存在hw_module_t中。而hw_module_t HMI
结构是一个全局结构,在gralloc.cpp中已经得到初始化了。这也是为什么每一个HAL模块都要定义并初始化一个名字为HAL_MODULE_INFO_SYM的hw_module_t结构
struct&private_module_t&HAL_MODULE_INFO_SYM&=&{&&&&&base:&{&&&&&&&&&common:&{&&&&&&&&&&&&&tag:&HARDWARE_MODULE_TAG,&&&&&&&&&&&&&version_major:&1,&&&&&&&&&&&&&version_minor:&0,&&&&&&&&&&&&&id:&GRALLOC_HARDWARE_MODULE_ID,&&&&&&&&&&&&&name:&&Graphics&Memory&Allocator&Module&,&&&&&&&&&&&&&author:&&The&Android&Open&Source&Project&,&&&&&&&&&&&&&methods:&&gralloc_module_methods&&&&&&&&&},&&&&&&&&&registerBuffer:&gralloc_register_buffer,&&&&&&&&&unregisterBuffer:&gralloc_unregister_buffer,&&&&&&&&&lock:&gralloc_lock,&&&&&&&&&unlock:&gralloc_unlock,&&&&&},&&&&&framebuffer:&0,&&&&&flags:&0,&&&&&numBuffers:&0,&&&&&bufferMask:&0,&&&&&lock:&PTHREAD_MUTEX_INITIALIZER,&&&&&currentBuffer:&0,&};&
回过头,回到FramebufferNativeWindow的构造函数处,接下来调用了err = framebuffer_open(module, &fbDev);framebuffer_open定义在fb.h中,是一个inline函数,其实最终调用了就是上面结构体中初始化的open函数,open函数指向gralloc_device_open,其实现为(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&=&(gralloc_context_t*)malloc(sizeof(*dev));&&&&&&&&&&&&&&&&&&&&memset(dev,&0,&sizeof(*dev));&&&&&&&&&&&&&&&&&&&&dev-&device.common.tag&=&HARDWARE_DEVICE_TAG;&&&&&&&&&dev-&device.common.version&=&0;&&&&&&&&&dev-&device.common.module&=&const_cast&hw_module_t*&(module);&&&&&&&&&dev-&device.common.close&=&gralloc_&&&&&&&&&&&dev-&device.alloc&&&=&gralloc_&&&&&&&&&dev-&device.free&&&&=&gralloc_&&&&&&&&&&&*device&=&&dev-&device.&&&&&&&&&status&=&0;&&&&&}&else&{&&&&&&&&&status&=&fb_device_open(module,&name,&device);&&&&&}&&&&&return&&}&
fb_device_open的定义如下所示(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));&&&&&&&&&memset(dev,&0,&sizeof(*dev));&&&&&&&&&&&&&&&&&&&&dev-&device.common.tag&=&HARDWARE_DEVICE_TAG;&&&&&&&&&dev-&device.common.version&=&0;&&&&&&&&&dev-&device.common.module&=&const_cast&hw_module_t*&(module);&&&&&&&&&dev-&device.common.close&=&fb_&&&&&&&&&dev-&device.setSwapInterval&=&fb_setSwapI&&&&&&&&&dev-&device.post&&&&&&&&&&&&=&fb_&&&&&&&&&dev-&device.setUpdateRect&=&0;&&&&&&&&&&&private_module_t*&m&=&(private_module_t*)&&&&&&&&&status&=&mapFrameBuffer(m);&&&&&&&&&if&(status&&=&0)&{&&&&&&&&&&&&&int&stride&=&m-&finfo.line_length&/&(m-&info.bits_per_pixel&&&&3);&&&&&&&&&&&&&int&format&=&(m-&info.bits_per_pixel&==&32)&&&&&&&&&&&&&&&&&&&&&&&&&&?&HAL_PIXEL_FORMAT_RGBX_8888&&&&&&&&&&&&&&&&&&&&&&&&&&:&HAL_PIXEL_FORMAT_RGB_565;&&&&&&&&&&&&&const_cast&uint32_t&&(dev-&device.flags)&=&0;&&&&&&&&&&&&&const_cast&uint32_t&&(dev-&device.width)&=&m-&info.&&&&&&&&&&&&&const_cast&uint32_t&&(dev-&device.height)&=&m-&info.&&&&&&&&&&&&&const_cast&int&&(dev-&device.stride)&=&&&&&&&&&&&&&&const_cast&int&&(dev-&device.format)&=&&&&&&&&&&&&&&const_cast&float&&(dev-&device.xdpi)&=&m-&&&&&&&&&&&&&&const_cast&float&&(dev-&device.ydpi)&=&m-&&&&&&&&&&&&&&const_cast&float&&(dev-&device.fps)&=&m-&&&&&&&&&&&&&&const_cast&int&&(dev-&device.minSwapInterval)&=&1;&&&&&&&&&&&&&const_cast&int&&(dev-&device.maxSwapInterval)&=&1;&&&&&&&&&&&&&*device&=&&dev-&device.&&&&&&&&&}&&&&&}&&&&&return&&}&
接下来的gralloc_open也是调用了gralloc_device_open,只不过name参数一个是GRALLOC_HARDWARE_GPU0,而另外一个是GRALLOC_HARDWARE_FB0,这两个函数分别得到alloc_device_t 和 framebuffer_device_t结构。到现在为止,gralloc模块的三个主要结构体,gralloc_module_t,alloc_device_t,framebuffer_device_t都已经获取到了。其中在fb_device_open函数中会获取实际的framebuffer设备(通常是/dev/graphics/fb0)的一些重要参数以及能力,比如分辨率信息以及支持多少个缓冲等,另外会把framebuffer映射到内测的地址保存到alloc_module_t中。android一般使用的都是双缓冲机制。具体代码如下(framebuffer.cpp),其中涉及到对private_module_t中一些成员的完善,涉及到gralloc_module_t以及private_handle_t等,其定义在gralloc_priv.h中,这两个结构中都保存了framebuffer的一些私有信息。
int&mapFrameBufferLocked(struct&private_module_t*&module)&{&&if&(module-&framebuffer)&{&return&0;&}&&&char&const&*&const&device_template[]&=&{&&/dev/graphics/fb%u&,&&/dev/fb%u&,&0&};&&&int&fd&=&-1;&int&i=0;&char&name[64];&&&while&((fd==-1)&&&&device_template[i])&{&snprintf(name,&64,&device_template[i],&0);&fd&=&open(name,&O_RDWR,&0);&i++;&}&if&(fd&&&0)&return&-&&&struct&fb_fix_screeninfo&&if&(ioctl(fd,&FBIOGET_FSCREENINFO,&&finfo)&==&-1)&return&-&&&struct&fb_var_screeninfo&&if&(ioctl(fd,&FBIOGET_VSCREENINFO,&&info)&==&-1)&return&-&&&info.reserved[0]&=&0;&info.reserved[1]&=&0;&info.reserved[2]&=&0;&info.xoffset&=&0;&info.yoffset&=&0;&info.activate&=&FB_ACTIVATE_NOW;&&&&&&info.yres_virtual&=&info.yres&*&NUM_BUFFERS;&uint32_t&flags&=&PAGE_FLIP;&if&(ioctl(fd,&FBIOPUT_VSCREENINFO,&&info)&==&-1)&{&info.yres_virtual&=&info.&flags&&=&~PAGE_FLIP;&ALOGW(&FBIOPUT_VSCREENINFO&failed,&page&flipping&not&supported&);&}&&&if&(info.yres_virtual&&&info.yres&*&2)&{&&info.yres_virtual&=&info.&flags&&=&~PAGE_FLIP;&ALOGW(&page&flipping&not&supported&(yres_virtual=%d,&requested=%d)&,&info.yres_virtual,&info.yres*2);&}&&&if&(ioctl(fd,&FBIOGET_VSCREENINFO,&&info)&==&-1)&return&-&&&uint64_t&refreshQuotient&=&(&uint64_t(&info.upper_margin&+&info.lower_margin&+&info.yres&)&*&(&info.left_margin&+&info.right_margin&+&info.xres&)&*&info.pixclock&);&&&&&int&refreshRate&=&refreshQuotient&&&0&?&(int)(0000LLU&/&refreshQuotient)&:&0;&&&if&(refreshRate&==&0)&{&&refreshRate&=&60*1000;&&}&&&if&(int(info.width)&&=&0&||&int(info.height)&&=&0)&{&&&info.width&=&((info.xres&*&25.4f)/160.0f&+&0.5f);&info.height&=&((info.yres&*&25.4f)/160.0f&+&0.5f);&}&&&float&xdpi&=&(info.xres&*&25.4f)&/&info.&float&ydpi&=&(info.yres&*&25.4f)&/&info.&float&fps&=&refreshRate&/&1000.0f;&&&ALOGI(&&using&(fd=%d)\n&&&id&=&%s\n&&&xres&=&%d&px\n&&&yres&=&%d&px\n&&&xres_virtual&=&%d&px\n&&&yres_virtual&=&%d&px\n&&&bpp&=&%d\n&&&r&=&%2u:%u\n&&&g&=&%2u:%u\n&&&b&=&%2u:%u\n&,&fd,&finfo.id,&info.xres,&info.yres,&info.xres_virtual,&info.yres_virtual,&info.bits_per_pixel,&info.red.offset,&info.red.length,&info.green.offset,&info.green.length,&info.blue.offset,&info.blue.length&);&&&ALOGI(&&width&=&%d&mm&(%f&dpi)\n&&&height&=&%d&mm&(%f&dpi)\n&&&refresh&rate&=&%.2f&Hz\n&,&info.width,&xdpi,&info.height,&ydpi,&fps&);&if&(ioctl(fd,&FBIOGET_FSCREENINFO,&&finfo)&==&-1)&return&-&&&if&(finfo.smem_len&&=&0)&return&-&module-&flags&=&&module-&info&=&&module-&finfo&=&&module-&xdpi&=&&module-&ydpi&=&&module-&fps&=&&&&&&&&&int&&size_t&fbSize&=&roundUpToPageSize(finfo.line_length&*&info.yres_virtual);&module-&framebuffer&=&new&private_handle_t(dup(fd),&fbSize,&0);&&&module-&numBuffers&=&info.yres_virtual&/&info.&module-&bufferMask&=&0;&&&void*&vaddr&=&mmap(0,&fbSize,&PROT_READ|PROT_WRITE,&MAP_SHARED,&fd,&0);&if&(vaddr&==&MAP_FAILED)&{&ALOGE(&Error&mapping&the&framebuffer&(%s)&,&strerror(errno));&return&-&}&module-&framebuffer-&base&=&intptr_t(vaddr);&memset(vaddr,&0,&fbSize);&return&0;&}&
由上面函数看出,mapFrameBufferLocked主要做了下面几件事情:
1. 打开framebuffer设备
2. 获取&fb_fix_screeninfo and fb_var_screeninfo
3. refill fb_var_screeninfo
4. 判断是否支持PAGE_FLIP
5. 计算刷新率
6. 打印gralloc信息
7. 填充private_module_t
8. mmap the framebuffer
看之前的HAL模块比如Camera模块,有一个hw_module_t结构和一个hw_device_t结构,而这里的gralloc模块却包含了两个hw_device_t结构,一个alloc_device_t和一个framebuffer_device_t结构。先看framebuffer_device_t定义:
framebuffer_device_t(fb.h):
typedef&struct&framebuffer_device_t&{&struct&hw_device_t&&&&&const&uint32_t&&&&&const&uint32_t&&const&uint32_t&&&&&const&int&&&&&const&int&&&&&const&float&&const&float&&&&&const&float&&&&&const&int&minSwapI&&&&const&int&maxSwapI&&&&const&int&numF&&&int&reserved[7];&&&&&&&&int&(*setSwapInterval)(struct&framebuffer_device_t*&window,&int&interval);&&&&&&&&&&&&&&&&&&&&&&&int&(*setUpdateRect)(struct&framebuffer_device_t*&window,&int&left,&int&top,&int&width,&int&height);&&&&&&&&&&&&&&&&&&&&&&int&(*post)(struct&framebuffer_device_t*&dev,&buffer_handle_t&buffer);&&&&&&&int&(*compositionComplete)(struct&framebuffer_device_t*&dev);&&&&&&&&void&(*dump)(struct&framebuffer_device_t*&dev,&char&*buff,&int&buff_len);&&&&&&&&&int&(*enableScreen)(struct&framebuffer_device_t*&dev,&int&enable);&&&void*&reserved_proc[6];&&&}&framebuffer_device_t;&
从这个结构看以看出,framebuffer_device_t里面主要保存了framebuffer相关的一些信息,例如分辨率,刷新率,framebuffer的数量等,另外,里面定义了一些操作framebuffer的函数,一下简单介绍其中几个函数。
1. static int fb_setSwapInterval(struct framebuffer_device_t* dev,&int interval)
这个函数基本没有用,因为maxSwapInterval=minSwapInterval= 1;
2.&int (*setUpdateRect)(struct framebuffer_device_t* window,&int left, int top, int width, int height);
这个函数是局部刷新用的,默认没有启用。和平台有关。
3.&int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
这个是最关键的函数。用来将图形缓冲区buffer的内容渲染到帧缓冲区中去,即显示在设备的显示屏中去。函数实现如下:
static&int&fb_post(struct&framebuffer_device_t*&dev,&buffer_handle_t&buffer)&{&if&(private_handle_t::validate(buffer)&&&0)&return&-EINVAL;&&&fb_context_t*&ctx&=&(fb_context_t*)&&&private_handle_t&const*&hnd&=&reinterpret_cast&private_handle_t&const*&(buffer);&private_module_t*&m&=&reinterpret_cast&private_module_t*&(&dev-&common.module);&&&if&(hnd-&flags&&&private_handle_t::PRIV_FLAGS_FRAMEBUFFER)&{&const&size_t&offset&=&hnd-&base&-&m-&framebuffer-&&m-&info.activate&=&FB_ACTIVATE_VBL;&m-&info.yoffset&=&offset&/&m-&finfo.line_&if&(ioctl(m-&framebuffer-&fd,&FBIOPUT_VSCREENINFO,&&m-&info)&==&-1)&{&ALOGE(&FBIOPUT_VSCREENINFO&failed&);&m-&base.unlock(&m-&base,&buffer);&return&-&}&m-&currentBuffer&=&&&&}&else&{&&&&&void*&fb_&void*&buffer_&&&m-&base.lock(&m-&base,&m-&framebuffer,&GRALLOC_USAGE_SW_WRITE_RARELY,&0,&0,&m-&info.xres,&m-&info.yres,&&fb_vaddr);&&&m-&base.lock(&m-&base,&buffer,&GRALLOC_USAGE_SW_READ_RARELY,&0,&0,&m-&info.xres,&m-&info.yres,&&buffer_vaddr);&&&memcpy(fb_vaddr,&buffer_vaddr,&m-&finfo.line_length&*&m-&info.yres);&&&m-&base.unlock(&m-&base,&buffer);&m-&base.unlock(&m-&base,&m-&framebuffer);&}&&&return&0;&}&
从fb_post的函数定义可以看出,其实现方式有两种方式,第一种方式是把Framebuffer的后buffer切为前buffer,然后通过IOCTRL机制告诉FB驱动切换DMA源地地址。
具体原理是这样的:当private_handle_t结构体hnd所描述的图形缓冲区是在系统帧缓冲区中分配的时候,即这个图形缓冲区的标志值flags的PRIV_FLAGS_FRAMEBUFFER位等于1的时候,我们是不需要将图形缓冲区的内容拷贝到系统帧缓冲区去的,因为我们将内容写入到图形缓冲区的时候,已经相当于是将内容写入到了系统帧缓冲区中去了。虽然在这种情况下,我们不需要将图形缓冲区的内容拷贝到系统帧缓冲区去,但是我们需要告诉系统帧缓冲区设备将要渲染的图形缓冲区作为系统当前的输出图形缓冲区,这样才可以将要渲染的图形缓冲区的内容绘制到设备显示屏来。例如,假设系统帧缓冲区有2个图形缓冲区,当前是以第1个图形缓冲区作为输出图形缓冲区的,这时候如果我们需要渲染第2个图形缓冲区,那么就必须告诉系统帧绘冲区设备,将第2个图形缓冲区作为输出图形缓冲区。这个实现方式的前提是Linux内核必须分配至少两个缓冲区大小的物理内存和实现切换的ioctrol,这个比较快速。
设置系统帧缓冲区的当前输出图形缓冲区是通过IO控制命令FBIOPUT_VSCREENINFO来进行的。IO控制命令FBIOPUT_VSCREENINFO需要一个fb_var_screeninfo结构体作为参数。从前面第3部分的内容可以知道,private_module_t结构体m的成员变量info正好保存在我们所需要的这个fb_var_screeninfo结构体。有了个m-&info这个fb_var_screeninfo结构体之后,我们只需要设置好它的成员变量yoffset的值(不用设置成员变量xoffset的值是因为所有的图形缓冲区的宽度是相等的),就可以将要渲染的图形缓冲区设置为系统帧缓冲区的当前输出图形缓冲区。fb_var_screeninfo结构体的成员变量yoffset保存的是当前输出图形缓冲区在整个系统帧缓冲区的纵向偏移量,即Y偏移量。我们只需要将要渲染的图形缓冲区的开始地址hnd-&base的值减去系统帧缓冲区的基地址m-&framebuffer-&base的值,再除以图形缓冲区一行所占据的字节数m-&finfo.line_length,就可以得到所需要的Y偏移量。
在执行IO控制命令FBIOPUT_VSCREENINFO之前,还会将作为参数的fb_var_screeninfo结构体的成员变量activate的值设置FB_ACTIVATE_VBL,表示要等到下一个垂直同步事件出现时,再将当前要渲染的图形缓冲区的内容绘制出来。这样做的目的是避免出现屏幕闪烁,即避免前后两个图形缓冲区的内容各有一部分同时出现屏幕中。
第二种方式是利用copy的方式来实现,比较耗时。当private_handle_t结构体hnd所描述的图形缓冲区是在内存中分配的时候,即这个图形缓冲区的标志值flags的PRIV_FLAGS_FRAMEBUFFER位等于0的时候,我们就需要将它的内容拷贝到系统帧缓冲区中去了。这个拷贝的工作是通过调用函数memcpy来完成的。在拷贝之前,我们需要三个参数。第一个参数是要渲染的图形缓冲区的起址地址,这个地址保存在参数buffer所指向的一个private_handle_t结构体中。第二个参数是要系统帧缓冲区的基地址,这个地址保存在private_module_t结构体m的成员变量framebuffer所指向的一个private_handle_t结构体中。第三个参数是要拷贝的内容的大小,这个大小就刚好是一个屏幕像素所占据的内存的大小。屏幕高度由m-&info.yres来描述,而一行屏幕像素所占用的字节数由m-&finfo.line_length来描述,将这两者相乘,就可以得到一个屏幕像素所占据的内存的大小。
在将一块内存缓冲区的内容拷贝到系统帧缓冲区中去之前,需要对这两块缓冲区进行锁定,以保证在拷贝的过程中,这两块缓冲区的内容不会被修改。这个锁定的工作是由Gralloc模块中的函数gralloc_lock来实现的。从前面第1部分的内容可以知道,Gralloc模块中的函数gralloc_lock的地址正好就保存在private_module_t结构体m的成员变量base所描述的一个gralloc_module_t结构体的成员函数lock中。
在调用函数gralloc_lock来锁定一块缓冲区之后,还可以通过最后一个输出参数来获得被锁定的缓冲区的开始地址,因此,通过调用函数gralloc_lock来锁定要渲染的图形缓冲区以及系统帧缓冲区,就可以得到前面所需要的第一个和第二个参数。
将要渲染的图形缓冲区的内容拷贝到系统帧缓冲区之后,就可以解除前面对它们的锁定了,这个解锁的工作是由Gralloc模块中的函数gralloc_unlock来实现的。从前面第1部分的内容可以知道,Gralloc模块中的函数gralloc_unlock的地址正好就保存在private_module_t结构体m的成员变量base所描述的一个gralloc_module_t结构体的成员函数unlock中。
以上是framebuffer_device_t结构相关的一些内容,其主要作用是渲染图形缓冲区来显示内容。下面在看看alloc_device_t的内容。
alloc_device_t结构的内容如下:
typedef&struct&alloc_device_t&{&struct&hw_device_t&&&&&&&&&&&&&&&&&&&int&(*alloc)(struct&alloc_device_t*&dev,&int&w,&int&h,&int&format,&int&usage,&buffer_handle_t*&handle,&int*&stride);&&&&&&&&&&&&&int&(*free)(struct&alloc_device_t*&dev,&buffer_handle_t&handle);&&&&&&&void&(*dump)(struct&alloc_device_t&*dev,&char&*buff,&int&buff_len);&&&void*&reserved_proc[7];&}&alloc_device_t;&
从其结构体成员可以看出,其主要作用是为请求者分配图形缓冲区。先看alloc函数的实现(gralloc.cpp):
static&int&gralloc_alloc(alloc_device_t*&dev,&&int&w,&int&h,&int&format,&int&usage,&&buffer_handle_t*&pHandle,&int*&pStride)&{&&if&(!pHandle&||&!pStride)&&return&-EINVAL;&&&size_t&size,&&&&int&align&=&4;&&int&bpp&=&0;&&switch&(format)&{&&case&HAL_PIXEL_FORMAT_RGBA_8888:&&case&HAL_PIXEL_FORMAT_RGBX_8888:&&case&HAL_PIXEL_FORMAT_BGRA_8888:&&bpp&=&4;&&break;&&case&HAL_PIXEL_FORMAT_RGB_888:&&bpp&=&3;&&break;&&case&HAL_PIXEL_FORMAT_RGB_565:&&case&HAL_PIXEL_FORMAT_RAW_SENSOR:&&bpp&=&2;&&break;&&default:&&return&-EINVAL;&&}&&size_t&bpr&=&(w*bpp&+&(align-1))&&&~(align-1);&&size&=&bpr&*&h;&&stride&=&bpr&/&&&&int&&&if&(usage&&&GRALLOC_USAGE_HW_FB)&{&&err&=&gralloc_alloc_framebuffer(dev,&size,&usage,&pHandle);&&}&else&{&&err&=&gralloc_alloc_buffer(dev,&size,&usage,&pHandle);&&}&&&if&(err&&&0)&{&&return&&&}&&&*pStride&=&&&return&0;&}&
参数format用来描述要分配的图形缓冲区的颜色格式,描述一个像素需要几个字节来表示。参数w表示要分配的图形缓冲区所保存的图像的宽度,将它乘以bpp,就可以得到保存一行像素所需要使用的字节数。我们需要将这个字节数对齐到4个字节边界,最后得到一行像素所需要的字节数就保存在变量bpr中。
参数h表示要分配的图形缓冲区所保存的图像的高度,将它乘以bpr,就可以得到保存整个图像所需要使用的字节数。将变量bpr的值除以变量bpp的值,就得到要分配的图形缓冲区一行包含有多少个像素点,这个结果需要保存在输出参数pStride中,以便可以返回给调用者。
参数usage用来描述要分配的图形缓冲区的用途。如果是用来在系统帧缓冲区中渲染的,即参数usage的GRALLOC_USAGE_HW_FB位等于1,那么就必须要系统帧缓冲区中分配,否则的话,就在内存中分配。注意,在内存中分配的图形缓冲区,最终是需要拷贝到系统帧缓冲区去的,以便可以将它所描述的图形渲染出来。函数gralloc_alloc_framebuffer用来在系统帧缓冲区中分配图形缓冲区,而函数gralloc_alloc_buffer用来在内存在分配图形缓冲区,接下来我们就来看看这两个函数的实现。
gralloc_alloc_framebuffer最终调用了gralloc_alloc_framebuffer_locked(gralloc.cpp):
static&int&gralloc_alloc_framebuffer_locked(alloc_device_t*&dev,&&size_t&size,&int&usage,&buffer_handle_t*&pHandle)&{&&private_module_t*&m&=&reinterpret_cast&private_module_t*&(&&dev-&common.module);&&&&&if&(m-&framebuffer&==&NULL)&{&&&&&&int&err&=&mapFrameBufferLocked(m);&&if&(err&&&0)&{&&return&&&}&&}&&&const&uint32_t&bufferMask&=&m-&bufferM&&const&uint32_t&numBuffers&=&m-&numB&&const&size_t&bufferSize&=&m-&finfo.line_length&*&m-&info.&&if&(numBuffers&==&1)&{&&&&&&&&int&newUsage&=&(usage&&&~GRALLOC_USAGE_HW_FB)&|&GRALLOC_USAGE_HW_2D;&&return&gralloc_alloc_buffer(dev,&bufferSize,&newUsage,&pHandle);&&}&&&if&(bufferMask&&=&((1LU&&numBuffers)-1))&{&&&&return&-ENOMEM;&&}&&&&&intptr_t&vaddr&=&intptr_t(m-&framebuffer-&base);&&private_handle_t*&hnd&=&new&private_handle_t(dup(m-&framebuffer-&fd),&size,&&private_handle_t::PRIV_FLAGS_FRAMEBUFFER);&&&&&for&(uint32_t&i=0&;&i&numBuffers&;&i++)&{&&if&((bufferMask&&&(1LU&&i))&==&0)&{&&m-&bufferMask&|=&(1LU&&i);&&break;&&}&&vaddr&+=&bufferS&&}&&&&hnd-&base&=&&&hnd-&offset&=&vaddr&-&intptr_t(m-&framebuffer-&base);&&*pHandle&=&&&&return&0;&}&
变量bufferMask用来描述系统帧缓冲区的使用情况,而变量numBuffers用来描述系统帧缓冲区可以划分为多少个图形缓冲区来使用,另外一个变量bufferSize用来描述设备显示屏一屏内容所占用的内存的大小。如果系统帧缓冲区只有一个图形缓冲区大小,即变量numBuffers的值等于1,那么这个图形缓冲区就始终用作系统主图形缓冲区来使用。在这种情况下,我们就不能够在系统帧缓冲区中分配图形缓冲区来给用户空间的应用程序使用,因此,这时候就会转向内存中来分配图形缓冲区,即调用函数gralloc_alloc_buffer来分配图形缓冲区。注意,这时候分配的图形缓冲区的大小为一屏内容的大小,即bufferSize。
如果bufferMask的值大于等于((1LU&&numBuffers)-1)的值,那么就说明系统帧缓冲区中的图形缓冲区全部都分配出去了,这时候分配图形缓冲区就失败了。例如,假设图形缓冲区的个数为2,那么((1LU&&numBuffers)-1)的值就等于3,即二制制0x11。如果这时候bufferMask的值也等于0x11,那么就表示第一个和第二个图形缓冲区都已经分配出去了。因此,这时候就不能再在系统帧缓冲区中分配图形缓冲区。
假设此时系统帧缓冲区中尚有空闲的图形缓冲区的,接下来函数就会创建一个private_handle_t结构体hnd来描述这个即将要分配出去的图形缓冲区。注意,这个图形缓冲区的标志值等于PRIV_FLAGS_FRAMEBUFFER,即表示这是一块在系统帧缓冲区中分配的图形缓冲区。
接下来的for循环从低位到高位检查变量bufferMask的值,并且找到第一个值等于0的位,这样就可以知道在系统帧缓冲区中,第几个图形缓冲区的是空闲的。注意,变量vadrr的值开始的时候指向系统帧缓冲区的基地址,在下面的for循环中,每循环一次它的值都会增加bufferSize。从这里就可以看出,每次从系统帧缓冲区中分配出去的图形缓冲区的大小都是刚好等于显示屏一屏内容大小的。最后分配出去的图形缓冲区的开始地址就保存在前面所创建的private_handle_t结构体hnd的成员变量base中,这样,用户空间的应用程序就可以直接将要渲染的图形内容拷贝到这个地址上去,这就相当于是直接将图形渲染到系统帧缓冲区中去。
在将private_handle_t结构体hnd返回给调用者之前,还需要设置它的成员变量offset,以便可以知道它所描述的图形缓冲区的起始地址相对于系统帧缓冲区的基地址的偏移量。
gralloc_alloc_buffer(gralloc.cpp)的实现如下:
static&int&gralloc_alloc_buffer(alloc_device_t*&dev,&size_t&size,&int&usage,&buffer_handle_t*&pHandle)&{&int&err&=&0;&int&fd&=&-1;&&&size&=&roundUpToPageSize(size);&&&fd&=&ashmem_create_region(&gralloc-buffer&,&size);&if&(fd&&&0)&{&ALOGE(&couldn't&create&ashmem&(%s)&,&strerror(-errno));&err&=&-&}&&&if&(err&==&0)&{&private_handle_t*&hnd&=&new&private_handle_t(fd,&size,&0);&gralloc_module_t*&module&=&reinterpret_cast&gralloc_module_t*&(&dev-&common.module);&err&=&mapBuffer(module,&hnd);&if&(err&==&0)&{&*pHandle&=&&}&}&&&ALOGE_IF(err,&&gralloc&failed&err=%s&,&strerror(-err));&&&return&&}&
它首先调用函数ashmem_create_region来创建一块匿名共享内存,接着再在这块匿名共享内存上分配一个图形缓冲区。注意,这个图形缓冲区也是使用一个private_handle_t结构体来描述的,不过这个图形缓冲区的标志值等于0,以区别于在系统帧缓冲区中分配的图形缓冲区。其中mapBuffer又把hnd所描述的一个图形缓冲区映射到当前进程的地址空间来。
以上内容就是alloc_device_t的相关内容。在private_module_t中有一个registerBuffer的函数指针,此函数是干什么的呢?在Android系统中,所有的图形缓冲区都是由SurfaceFlinger服务分配的,而当一个图形缓冲区被分配的时候,它会同时被映射到请求分配的进程的地址空间去,即分配的过程同时也包含了注册的过程。但是对用户空间的其它的应用程序来说,它们所需要的图形缓冲区是在由SurfaceFlinger服务分配的,因此,当它们得到SurfaceFlinger服务分配的图形缓冲区之后,还需要将这块图形缓冲区映射到自己的地址空间来,以便可以使用这块图形缓冲区。这个映射的过程即为我们接下来要分析的图形缓冲区注册过程。
由于在系统帧缓冲区中分配的图形缓冲区只在SurfaceFlinger服务中使用,而SurfaceFlinger服务在初始化系统帧缓冲区的时候,已经将系统帧缓冲区映射到自己所在的进程中来了,因此,函数gralloc_map如果发现要注册的图形缓冲区是在系统帧缓冲区分配的时候,那么就不需要再执行映射图形缓冲区的操作了。
如果要注册的图形缓冲区是在内存中分配的,即它的标志值flags的PRIV_FLAGS_FRAMEBUFFER位等于1,那么接下来就需要将它映射到当前进程的地址空间来了。由于要注册的图形缓冲区是在文件描述符hnd-&fd所描述的一块匿名共享内存中分配的,因此,我们只需要将文件描述符hnd-&fd所描述的一块匿名共享内存映射到当前进程的地址空间来,就可以将参数hnd所描述的一个图形缓冲区映射到当前进程的地址空间来。
由于映射文件描述符hnd-&fd得到的是一整块匿名共享内存在当前进程地址空间的基地址,而要注册的图形缓冲区可能只占据这块匿名共享内存的某一小部分,因此,我们还需要将要注册的图形缓冲区的在被映射的匿名共享内存中的偏移量hnd-&offset加上被映射的匿名共享内存的基地址hnd-&base,才可以得到要注册的图形缓冲区在当前进程中的访问地址,这个地址最终又被写入到hnd-&base中去。
参考文档:http://blog.csdn.net/luoshengyang/article/details/7747932
【编辑推荐】【责任编辑: TEL:(010)】
大家都在看猜你喜欢
原创头条头条头条头条
24H热文一周话题本月最赞
讲师:425564人学习过
讲师:111860人学习过
讲师:125189人学习过
精选博文论坛热帖下载排行
本书共分两篇,15章。其中前6章为网络理论基础篇,介绍的是基本的网络技术,包括计算机网络分类、网络通信协议、IP地址和网线制作等。在第...
订阅51CTO邮刊}

我要回帖

更多关于 getjsmainmodulename 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信