功能:Galloc模块是显示框架的硬件抽象层,主要是封装了/dev/graphics/fb%d设备文件的操作,
为框架层提供接口。
实现:Gralloc是HAl中的模块,会被编译成动态链接库。框架层会将动态链接库加载到内存中,
并利用导出符号得到封装的方法。
问题: 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) {
continue;
}
//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) break;
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH1, name, prop);
if (access(path, R_OK) == 0) break;
} else {
//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) break;
}
}
status = -ENOENT;
if (i < HAL_VARIANT_KEYS_COUNT+1) {
//3.加载gralloc.xx.so到内存
status = load(class_id, path, module);
}
return status;
}
函数很简单,在几个路径下查询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 = handle;
//3.返回给调用者hw_module_t
*pHmi = hmi;
return status;
}
由此分析可知,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指针。
答:封装了一个模块两个设备,提供了映射、分配、渲染的三个主要功能。
从APP层到驱动层,图像显示的过程:
应用程序首选需要分配一个图像缓冲区并使用它,但是有由于app在java虚拟机运行中而图形缓冲区分配是在本地代码实现的,因此需要一个映射的过程将图像缓冲区映射到应用的地址空间中,这样应用程序就可以使用图形缓冲区了;而要让图形显示到LCD中,需要把数据写入设备文件里,这里还需要一个渲染的过程用于将图像缓冲区的数据送到帧缓冲区中。
由上面的分析可知,HAL层需要提供的抽象操作包括:分配、映射、渲染。而Gralloc模块中将这些操作封装到了下面的结构中。
1.加载Gralloc模块
打开gralloc设备
打开fb设备
2.分配图形缓冲区 (gralloc设备)
3.图形缓冲区映射 (Gralloc模块)
4.渲染图形缓冲区 (fb设备)
答:从功能角度来分析结构更容易。
忽略掉继承封装这些细节,下面画出了Gralloc模块的内部结构,这样再分析代码就很清晰了
galloc设备的方式实现在gralloc.cpp中, fb设备的方法实现在framebuffer.cpp中, 映射的方法实现在mapper.cpp中
struct private_module_t {
gralloc_module_t base;
private_handle_t* framebuffer; //指向帧缓冲区的句柄
uint32_t flags; //是否支持双缓冲
uint32_t numBuffers; //图形缓冲区的个数
uint32_t bufferMask; //图形缓冲区的使用情况
pthread_mutex_t lock; //互斥锁
buffer_handle_t currentBuffer; //正在被使用的缓冲区 native_handle* buffer_handle_t;
int pmem_master;
void* pmem_master_base;
struct fb_var_screeninfo info;
struct fb_fix_screeninfo finfo;
float xdpi;
float ydpi;
float fps;
};
gralloc_module_t定义在文件hardware/libhardware/include/hardware/gralloc.h
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_t common;
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_t common;
/* flags describing some attributes of the framebuffer */
const uint32_t flags;
/* dimensions of the framebuffer in pixels */
const uint32_t width;
const uint32_t height;
/* frambuffer stride in pixels */
const int stride;
/* framebuffer pixel format */
const int format;
/* resolution of the framebuffer's display panel in pixel per inch*/
const float xdpi;
const float ydpi;
/* framebuffer's display panel refresh rate in frames per second */
const float fps;
/* min swap interval supported by this framebuffer */
const int minSwapInterval;
/* max swap interval supported by this framebuffer */
const int maxSwapInterval;
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_device_open定义在文件hardware/libhardware/modules/gralloc/gralloc.cpp
这里使用hw_module_t方法中的open操作打开并返回了alloc_device_t设备
struct gralloc_context_t {
alloc_device_t 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;
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_close;
dev->device.alloc = gralloc_alloc;
dev->device.free = gralloc_free;
*device = &dev->device.common;
status = 0;
}
......
return status;
}
fb_device_open定义在文件hardware/libhardware/modules/gralloc/framebuffer.cpp
struct fb_context_t {
framebuffer_device_t 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_device;
status = gralloc_open(module, &gralloc_device);
if (status < 0)
return status;
/* 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_close;
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;
dev->device.setUpdateRect = 0;
private_module_t* m = (private_module_t*)module;
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;
#endif
const_cast<uint32_t&>(dev->device.flags) = 0;
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.stride) = stride;
const_cast<int&>(dev->device.format) = format;
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
const_cast<int&>(dev->device.minSwapInterval) = 1;
const_cast<int&>(dev->device.maxSwapInterval) = 1;
*device = &dev->device.common;
}
}
return status;
}