Android 中 lcd 是一个帧缓冲设备,驱动程序通过处理器的 lcd 控制器将物理内存的一段区域设置为显存,如果向这段内存区域写入数据就会马上在 lcd 上显示出来。Android 在 HAL 中提供了gralloc 模块,封装了用户层对帧缓冲设备的所有操作接口,并通过 SurfaceFlinger 服务向应用提供显示支持。在启动过程中系统会加载 gralloc 模块,然后打开帧缓冲设备,获取设备的各种参数并完成 gralloc 模块的初始化。当应用程序需要把内容显示到 lcd 上时,需要通过 gralloc 模块申请一块图形缓冲区,然后将这块图形缓冲区映射到自己的地址空间并写入内容即可。当应用程序不再需要这块图形缓冲区时需要通过 gralloc 模块释放掉,然后解除对缓冲区的映射。
1、基础数据结构
gralloc 模块通过 struct private_module_t 来描述,该结构定义如下:
- 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;
-
- int orientation;
-
- enum {
- PRIV_USAGE_LOCKED_FOR_POST = 0x80000000
- };
- };
该结构的成员记录了 gralloc 模块的各种参数,主要为模块自己使用,应用程序操作的
图形缓冲区的数据结构是
struct private_handle_t,定义如下:
- #ifdef __cplusplus
- struct private_handle_t : public native_handle {
- #else
- struct private_handle_t {
- struct native_handle nativeHandle;
- #endif
-
- enum {
- PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
- PRIV_FLAGS_USES_PMEM = 0x00000002,
- PRIV_FLAGS_USES_MMEM = 0x00000004,
- PRIV_FLAGS_NEEDS_FLUSH = 0x00000008,
- };
-
- enum {
- LOCK_STATE_WRITE = 1<<31,
- LOCK_STATE_MAPPED = 1<<30,
- LOCK_STATE_READ_MASK = 0x3FFFFFFF
- };
-
-
-
- int fd;
-
- int magic;
-
-
- int flags;
- int size;
- int offset;
-
- int phys;
- int base;
- int lockState;
- int writeOwner;
- int pid;
-
- #ifdef __cplusplus
- static const int sNumInts = 9;
- static const int sNumFds = 1;
- static const int sMagic = 0x3141592;
-
- private_handle_t(int fd, int size, int flags) :
- fd(fd), magic(sMagic), flags(flags), size(size), offset(0),
- phys(0), base(0), lockState(0), writeOwner(0), pid(getpid())
- {
- version = sizeof(native_handle);
- numInts = sNumInts;
- numFds = sNumFds;
- }
- ~private_handle_t() {
- magic = 0;
- }
-
- bool usesPhysicallyContiguousMemory() {
- return (flags & PRIV_FLAGS_USES_PMEM) != 0;
- }
-
-
- static int validate(const native_handle* h) {
- const private_handle_t* hnd = (const private_handle_t*)h;
- if (!h || h->version != sizeof(native_handle) ||
- h->numInts != sNumInts || h->numFds != sNumFds ||
- hnd->magic != sMagic)
- {
- LOGE("invalid gralloc handle (at %p)", h);
- return -EINVAL;
- }
- return 0;
- }
-
- static private_handle_t* dynamicCast(const native_handle* in) {
- if (validate(in) == 0) {
- return (private_handle_t*) in;
- }
- return NULL;
- }
- #endif
- };
图形缓冲区的操作接口由结构 struct gralloc_module_t 定义:
- 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);
-
- int (*perform)(struct gralloc_module_t const* module,
- int operation, ... );
-
-
- void* reserved_proc[7];
- } gralloc_module_t;
gralloc 设备则用结构 struct alloc_device_t 来描述,其定义如下:
- 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;
帧缓冲设备则采用结构
struct framebuffer_device_t 描述:
- 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;
-
- 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;
其中成员函数
post 对应用程序来说是最重要的接口,它将完成数据写入显存的工作。
2、gralloc 模块
HAL 中通过 hw_get_module 接口加载指定 id 的模块,并获得一个 hw_module_t 结构来打开设备,流程如下:
- #define HAL_LIBRARY_PATH1 "/system/lib/hw"
- #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
-
- static const char *variant_keys[] = {
- "ro.hardware",
- "ro.product.board",
- "ro.board.platform",
- "ro.arch"
- };
-
- static const int HAL_VARIANT_KEYS_COUNT =
- (sizeof(variant_keys)/sizeof(variant_keys[0]));
-
- int hw_get_module(const char *id, const struct hw_module_t **module)
- {
- int status;
- int i;
- const struct hw_module_t *hmi = NULL;
- char prop[PATH_MAX];
- char path[PATH_MAX];
-
-
-
-
-
-
-
-
-
- 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_PATH1, id, prop);
- if (access(path, R_OK) == 0) break;
-
- snprintf(path, sizeof(path), "%s/%s.%s.so",
- HAL_LIBRARY_PATH2, id, prop);
- if (access(path, R_OK) == 0) break;
- } else {
- snprintf(path, sizeof(path), "%s/%s.default.so",
- HAL_LIBRARY_PATH1, id);
- if (access(path, R_OK) == 0) break;
- }
- }
-
- status = -ENOENT;
- if (i < HAL_VARIANT_KEYS_COUNT+1) {
-
- status = load(id, path, module);
- }
-
- return status;
- }
函数会在 /system/lib/hw 或者 /vendor/lib/hw 目录中去寻找gralloc.xxx.so 文件,如果找到了就调用load接口完成加载。最终会调用 gralloc_device_open完成 gralloc 设备成员的初始化:
- 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));
-
-
- 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_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;
- }
在 android 系统中,所有的图形缓冲区都是由
SurfaceFlinger 服务分配的,在系统帧缓冲区中分配的图形缓冲区只在 SurfaceFlinger 服务中使用,而在内存中分配的图形缓冲区既可以在 SurfaceFlinger 服务中使用,也可以在其它的应用程序中使用,当应用程序请求 SurfaceFlinger 服务分配图形缓冲区时会发生
两次映射:服务所在的进程首先会将申请到的缓冲区映射至服务的地址空间,然后应用程序使用这个图形缓冲时再将其映射至应用程序的地址空间。分配函数的实现如下:
- static int gralloc_alloc_framebuffer(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);
- pthread_mutex_lock(&m->lock);
- int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);
- pthread_mutex_unlock(&m->lock);
- return err;
- }
-
- 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) {
- LOGE("couldn't create ashmem (%s)", strerror(-errno));
- err = -errno;
- }
-
- 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 = hnd;
- }
- }
-
- LOGE_IF(err, "gralloc failed err=%s", strerror(-err));
-
- return err;
- }
-
-
-
- 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, stride;
-
- 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_RGBA_5551:
- case HAL_PIXEL_FORMAT_RGBA_4444:
- bpp = 2;
- break;
- default:
- return -EINVAL;
- }
- size_t bpr = (w*bpp + (align-1)) & ~(align-1);
- size = bpr * h;
- stride = bpr / bpp;
-
- int err;
- 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 err;
- }
-
- *pStride = stride;
- return 0;
- }
3、fb 模块
在 gralloc_device_open 中会根据传递的参数分别初始化两个设备,定义如下:
- #define GRALLOC_HARDWARE_FB0 "fb0"
- #define GRALLOC_HARDWARE_GPU0 "gpu0"
如果参数不是 "gpu0" 则会调用
fb_device_open 初始化 fb 设备,主要流程和打开 gralloc 基本一致,在函数中会通过调用 mapFrameBuffer->mapFrameBufferLocked 获取帧缓存设备的参数并将其设备节点映射到用户空间,流程如下:
- 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 -errno;
-
- struct fb_fix_screeninfo finfo;
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- struct fb_var_screeninfo info;
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- info.reserved[0] = 0;
- info.reserved[1] = 0;
- info.reserved[2] = 0;
- info.xoffset = 0;
- info.yoffset = 0;
- info.activate = FB_ACTIVATE_NOW;
-
- info.bits_per_pixel = 32;
- info.red.offset = 16;
- info.red.length = 8;
- info.green.offset = 8;
- info.green.length = 8;
- info.blue.offset = 0;
- info.blue.length = 8;
- info.transp.offset = 24;
- info.transp.length = 8;
-
-
-
-
- info.yres_virtual = info.yres * NUM_BUFFERS;
-
-
- uint32_t flags = PAGE_FLIP;
- if (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("FBIOPAN_DISPLAY failed, page flipping not supported");
- }
-
- if (info.yres_virtual < info.yres * 2) {
-
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
- info.yres_virtual, info.yres*2);
- }
-
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- int refreshRate = 1000000000000000LLU /
- (
- uint64_t( info.upper_margin + info.lower_margin + info.yres )
- * ( info.left_margin + info.right_margin + info.xres )
- * info.pixclock
- );
-
- 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.width;
- float ydpi = (info.yres * 25.4f) / info.height;
- float fps = refreshRate / 1000.0f;
-
- LOGI( "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
- );
-
- LOGI( "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 -errno;
-
- if (finfo.smem_len <= 0)
- return -errno;
-
- module->flags = flags;
- module->info = info;
- module->finfo = finfo;
- module->xdpi = xdpi;
- module->ydpi = ydpi;
- module->fps = fps;
-
-
-
-
-
- int err;
- size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
- module->framebuffer = new private_handle_t(dup(fd), fbSize,
- private_handle_t::PRIV_FLAGS_USES_PMEM);
-
- module->numBuffers = info.yres_virtual / info.yres;
- module->bufferMask = 0;
-
- void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- if (vaddr == MAP_FAILED) {
- LOGE("Error mapping the framebuffer (%s)", strerror(errno));
- return -errno;
- }
- module->framebuffer->base = intptr_t(vaddr);
- memset(vaddr, 0, fbSize);
- return 0;
- }
fb 模块最重要的工作就是将应用程序指定的内容写入显存中,是通过函数 fb_post 完成的,流程如下:
-
- static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
- {
- unsigned int phys;
- void* virt;
- int pitch;
- int format;
-
-
- if (private_handle_t::validate(buffer) < 0)
- return -EINVAL;
-
- fb_context_t* ctx = (fb_context_t*)dev;
-
- 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 (m->currentBuffer) {
- m->base.unlock(&m->base, m->currentBuffer);
- m->currentBuffer = 0;
- }
-
- if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
- m->base.lock(&m->base, buffer,
- private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
- 0, 0, m->info.xres, m->info.yres, NULL);
-
- const size_t offset = hnd->base - m->framebuffer->base;
-
-
-
- m->info.activate = FB_ACTIVATE_VBL;
- m->info.yoffset = offset / m->finfo.line_length;
-
- if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) == -1) {
- LOGE("FBIOPAN_DISPLAY failed");
- m->base.unlock(&m->base, buffer);
- return -errno;
- }
-
- if (UNLIKELY(mDebugFps)) {
- debugShowFPS();
- }
-
- #ifdef SNAPSHOT
- dumpfile((void*)hnd->base, m->info.xres, m->info.yres);
- #endif
- m->currentBuffer = buffer;
- } else {
-
-
- LOGD("copy bit.\n");
- void* fb_vaddr;
- void* buffer_vaddr;
-
-
- 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;
- }