首页 > 系统 > Android > 正文

【图形图像】Android SurfaceFlinger之Gralloc

2019-11-08 00:35:34
字体:
来源:转载
供稿:网友

1、SurfaceFlinger模块

Android中SurfaceFlinger与其它模块的关系图如下所示:

这里写图片描述

上图中,最底层的是linux内核提供的framebuffer显示驱动,设备节点为/dev/graphics/fb*或/dev/fb*,其中fb0表示第一个monitor。HAL层提供了Gralloc和Composer,其中Gralloc包括fb和gralloc两个设备,fb负责打开内核中的framebuffer、初始化配置,gralloc管理帧缓冲区的分配和释放,而Composer为UI合成提供接口,直接使用者是SurfaceFlinger中的HWComposer,HWComposer管理HAL层的Composer并负责VSync信号的产生和控制。FramebufferNativeWindow是OpengGL ES在Android平台上本地化的中介之一,EGL为OpengGL ES配置本地窗口,OpengGL ES支持软件实现libagl和硬件实现libhgl,DisplayDevice用于构建OpenGL ES运行环境。

2、HAL与Gralloc

HAL是位于Linux Kernel之上的硬件抽象层,旨在降低Android系统与硬件的耦合性,提供了统一的硬件无关的抽象接口。Android的各子系统通常不会直接使用内核驱动,而是由HAL层来间接引用底层架构,显示系统也同样如此,它借助于HAL层来操作帧缓冲区,而完成这一中介任务的就是Gralloc,Android中源码位置在hardware/libhardware/modules/gralloc/,包括三个文件,framebuffer.cpp、gralloc.cpp和mapper.cpp。

为了做到与硬件无关的抽象配置,在hardware/libhardware/include/hardware.h中定义了三个重要的数据结构,如下所示:

struct hw_module_t;struct hw_module_methods_t;struct hw_device_t;

其中,hw_module_t有如下要求:

/** * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM * and the fields of this data structure must begin with hw_module_t * followed by module specific information. */typedef struct hw_module_t { uint32_t tag; uint16_t module_api_version; uint16_t hal_api_version; const char *id; const char *name; const char *author; struct hw_module_methods_t* methods; void* dso;#ifdef __LP64__ uint64_t reserved[32-7];#else uint32_t reserved[32-7];#endif} hw_module_t;

也就是说,每个硬件模块都要有一个名为HAL_MODULE_INFO_SYM的变量,这个变量的数据结构的第一个字段类型为hw_module_t,犹如面向对象编程语言如C++的继承机制一样,以实现接口抽象。下面看一下Gralloc是如何实现的。

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,};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; int pmem_master; void* pmem_master_base; struct fb_var_screeninfo info; struct fb_fix_screeninfo finfo; float xdpi; float ydpi; float fps;};typedef struct gralloc_module_t { struct hw_module_t common; 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); /* reserved for future use */ int (*perform)(struct gralloc_module_t const* module, int Operation, ... ); int (*lock_ycbcr)(struct gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, struct android_ycbcr *ycbcr); int (*lockAsync)(struct gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, void** vaddr, int fenceFd); int (*unlockAsync)(struct gralloc_module_t const* module, buffer_handle_t handle, int* fenceFd); int (*lockAsync_ycbcr)(struct gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, struct android_ycbcr *ycbcr, int fenceFd); void* reserved_proc[3];} gralloc_module_t;

可以看出,HAL_MODULE_INFO_SYM通过private_module_t、gralloc_module_t最终包含了hw_module_t。

3、Gralloc模块加载过程

Gralloc模块加载通过hardware/libhardware/include/hardware.h声明的如下函数完成。

int hw_get_module(const char *id, const struct hw_module_t **module);#define GRALLOC_HARDWARE_MODULE_ID "gralloc"

通过hw_get_module加载Gralloc时,参数id为GRALLOC_HARDWARE_MODULE_ID,随后会走到如下hw_get_module_by_class函数,其中参数inst为NULL。

int hw_get_module_by_class(const char *class_id, const char *inst, const struct hw_module_t **module){ int i = 0; char prop[PATH_MAX] = {0}; char path[PATH_MAX] = {0}; char name[PATH_MAX] = {0}; char prop_name[PATH_MAX] = {0}; if (inst) snprintf(name, PATH_MAX, "%s.%s", class_id, inst); else strlcpy(name, class_id, PATH_MAX); snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name); if (property_get(prop_name, prop, NULL) > 0) { if (hw_module_exists(path, sizeof(path), name, prop) == 0) { goto found; } } for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) { if (property_get(variant_keys[i], prop, NULL) == 0) { continue; } if (hw_module_exists(path, sizeof(path), name, prop) == 0) { goto found; } } if (hw_module_exists(path, sizeof(path), name, "default") == 0) { goto found; } return -ENOENT;found: return load(class_id, path, module);}

hw_get_module_by_class的实现逻辑是先获取ro.hardware.graphic属性,属性获取成功后就到指定的目录检查gralloc库是否存在,对于64位的机器来说在如下几个目录检查:

#define HAL_LIBRARY_PATH1 "/system/lib64/hw"#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"#define HAL_LIBRARY_PATH3 "/odm/lib64/hw"

库的名字为gralloc..so。如果ro.hardware.graphic属性获取失败或者在指定的目录找不到gralloc库时就逐个获取如下几个属性:

"ro.hardware""ro.product.board""ro.board.platform""ro.arch"

属性获取成功后,再到上面提到的几个目录查找gralloc..so,如果还是找不到,最后则查找Android默认的库gralloc.default.so。上面几个步骤中一旦找到了gralloc库,就立即通过dlopen函数打开,否则gralloc模块加载失败。dlopen成功后,通过dlsym获取HAL_MODULE_INFO_SYM_AS_STR即名为HMI的函数地址,dlsym成功后再判断其模块id是否为gralloc,如果是的话,预示着gralloc模块加载成功,最后将dlopen结果保存到hw_module_t的dso成员,即一开始调用hw_get_module函数的参数module中,这是个二级指针,至此,Gralloc模块加载完成。总结一下,Gralloc模块的加载就是在指定的几个目录中逐个查找gralloc库,因为gralloc库有不同的表示形式,gralloc库存在的话进而使用dlopen、dlsym进行处理。

4、Gralloc接口

从上面的数据结构中可以看出,gralloc_module_t继承了hw_module_t,进而包含了如下hw_module_methods_t:

typedef struct hw_module_methods_t { int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device);} hw_module_methods_t;

这是一个重要的接口,目前只是一个函数指针open,用来打开某个特定的设备文件。既然有open,那么必然有close,在如下的hw_device_t中。

/** * Every device data structure must begin with hw_device_t * followed by module specific public methods and attributes. */typedef struct hw_device_t { uint32_t tag; uint32_t version;#ifdef __LP64__ uint64_t reserved[12];#else uint32_t reserved[12];#endif int (*close)(struct hw_device_t* device);} hw_device_t;

上述open用来打开设备gpu0和fb0,两者用法类似,如下函数所示:

// gralloc.h#define GRALLOC_HARDWARE_GPU0 "gpu0"static inline int gralloc_open(const struct hw_module_t* module, struct alloc_device_t** device) { return module->methods->open(module, GRALLOC_HARDWARE_GPU0, TO_HW_DEVICE_T_OPEN(device));}static inline int gralloc_close(struct alloc_device_t* device) { return device->common.close(&device->common);}// fb.h#define GRALLOC_HARDWARE_FB0 "fb0"static inline int framebuffer_open(const struct hw_module_t* module, struct framebuffer_device_t** device) { return module->methods->open(module, GRALLOC_HARDWARE_FB0, TO_HW_DEVICE_T_OPEN(device));}static inline int framebuffer_close(struct framebuffer_device_t* device) { return device->common.close(&device->common);}

上面提到了每一个HAL模块如这里的Gralloc都应该有一个HAL_MODULE_INFO_SYM,其中指定了open函数指针为gralloc_device_open函数,具体如下:

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; } else { status = fb_device_open(module, name, device); } return status;}

从上面的gralloc_device_open可以看出,会判断打开gpu还是fb,下面分开介绍。

5、device-gpu

gpu相关device的数据结构如下:

struct gralloc_context_t { alloc_device_t device;};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); void (*dump)(struct alloc_device_t *dev, char *buff, int buff_len); void* reserved_proc[7];} alloc_device_t;

在gralloc_device_open中,malloc一个gralloc_context_t,然后指定了对应的close、alloc和free接口,其中close用于free刚刚malloc的gralloc_context_t,alloc和free用于管理帧缓冲区,涉及字节对齐(包括页对齐)、共享内存、设备管理、内存映射等,以及一个新的数据结构private_handle_t(管理文件描述符),后面着重说明。

6、device-fb

framebuffer相关device的数据结构如下:

struct fb_context_t { framebuffer_device_t device;};typedef struct framebuffer_device_t { struct hw_device_t common; const uint32_t flags; const uint32_t width; const uint32_t height; const int stride; const int format; const float xdpi; const float ydpi; const float fps; const int minSwapInterval; const int maxSwapInterval; const int numFramebuffers; 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;

fb_device_open函数如下:

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_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) ? (m->info.red.offset ? HAL_PIXEL_FORMAT_BGRA_8888 : 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.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;}

可以看出,fb与gpu设备的处理类似,重要的一步在与mapFrameBuffer,此时有posix mutex作同步保护。这一步才是真正的open操作,首先尝试打开/dev/graphics/fb0、/dev/fb0,成功则继续,随后是一些ioctl操作,用于获取屏幕信息,并通过这些屏幕信息算出fb的长度,最后mmap映射到刚打开的fb0设备文件,长度为刚算出的fb长度。在打开gpu0时,可以像fb0一样分配framebuffer,也可以是普通的buffer,这个普通的buffer映射的为共享内存区,即文件描述符通过ashmem_create_region函数(属于Android的libcutils库)创建。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表