Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析(6)
16lz
2021-01-26
函数fb_device_open在打开fb设备的过程中,会调用另外一个函数mapFrameBuffer来获得系统帧缓冲区的信息,并且将这些信息保存在参数module所描述的一个private_module_t结构体的各个成员变量中。有了系统帧缓冲区的信息之后,函数fb_device_open接下来就可以对前面所打开的一个fb设备的各个成员变量进行初始化。这些成员变量的含义可以参考前面对结构体framebuffer_device_t的介绍。接下来我们只简单介绍一下结构体framebuffer_device_t的成员变量stride和format的初始化过程。 变量m的成员变量finfo的类型为fb_fix_screeninfo,它是在函数mapFrameBuffer中被始化的。fb_fix_screeninfo是在内核中定义的一个结构体,用来描述设备显示屏的固定属性信息,其中,它的成员变量line_length用来描述显示屏一行像素总共所占用的字节数。 变量m的另外一个成员变量info的类型为fb_var_screeninfo,它也是在函数mapFrameBuffer中被始化的。fb_var_screeninfo也是内核中定义的一个结构体,用来描述可以动态设置的显示屏属性信息,其中,它的成员变量bits_per_pixel用来描述显示屏每一个像素所占用的位数。 这样,我们将m->info.bits_per_pixel的值向右移3位,就可以得到显示屏每一个像素所占用的字节数。用显示屏每一个像素所占用的字节数去除显示屏一行像素总共所占用的字节数m->finfo.line_length,就可以得到显示屏一行有多少个像素点。这个值最终就可以保存在前面所打开的fb设备的成员变量stride中。 当显示屏每一个像素所占用的位数等于32的时候,那么前面所打开的fb设备的像素格式format就会被设置为HAL_PIXEL_FORMAT_RGBX_8888,否则的话,就会被设置为HAL_PIXEL_FORMAT_RGB_565。另一方面,如果在编译的时候定义了NO_32BPP宏,即不要使用32位来描述一个像素,那么函数fb_device_open就会强制将前面所打开的fb设备的像素格式format设置为HAL_PIXEL_FORMAT_RGB_565。 函数mapFrameBuffer除了用来获得系统帧缓冲区的信息之外,还会将系统帧缓冲区映射到当前进程的地址空间来。在Android系统中,Gralloc模块中的fb设备是由SurfaceFlinger服务来负责打开和管理的,而SurfaceFlinger服是运行System进程中的,因此,系统帧缓冲区实际上是映射到System进程的地址空间中的。 函数mapFrameBuffer实现在文件hardware/libhardware/modules/gralloc/framebuffer.cpp,如下所示:
这段代码在首先在系统中检查是否存在设备文件/dev/graphics/fb0或者/dev/fb0。如果存在的话,那么就调用函数open来打开它,并且将得到的文件描述符保存在变量fd中。这样,接下来函数mapFrameBufferLocked就可以通过文件描述符fd来与内核中的帧缓冲区驱动程序交互。 继续往下看函数mapFrameBufferLocked:
- static int mapFrameBuffer(struct private_module_t* module)
- {
- pthread_mutex_lock(&module->lock);
- int err = mapFrameBufferLocked(module);
- pthread_mutex_unlock(&module->lock);
- return err;
- }
- int mapFrameBufferLocked(struct private_module_t* module)
- {
- // already initialized...
- 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;
这段代码在首先在系统中检查是否存在设备文件/dev/graphics/fb0或者/dev/fb0。如果存在的话,那么就调用函数open来打开它,并且将得到的文件描述符保存在变量fd中。这样,接下来函数mapFrameBufferLocked就可以通过文件描述符fd来与内核中的帧缓冲区驱动程序交互。 继续往下看函数mapFrameBufferLocked:
- 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;
- #if defined(NO_32BPP)
- /*
- * Explicitly request 5/6/5
- */
- info.bits_per_pixel = 16;
- info.red.offset = 11;
- info.red.length = 5;
- info.green.offset = 5;
- info.green.length = 6;
- info.blue.offset = 0;
- info.blue.length = 5;
- info.transp.offset = 0;
- info.transp.length = 0;
- #endif
- /*
- * Request NUM_BUFFERS screens (at lest 2 for page flipping)
- */
- info.yres_virtual = info.yres * NUM_BUFFERS;
- uint32_t flags = PAGE_FLIP;
- if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
- }
- if (info.yres_virtual < info.yres * 2) {
- // we need at least 2 for page-flipping
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
- info.yres_virtual, info.yres*2);
- }
另一方面,如果调用函数ioctl成功,但是最终获得的显示屏的虚拟分辨率的高度值小于可视分辨率的高度值的2倍,那么也说明系统帧缓冲区在硬件上不支持双缓冲。在这种情况下,接下来的代码也会重新将显示屏的虚拟分辨率的高度值设置为可视分辨率的高度值,并且将变量flags的PAGE_FLIP位置为0。 再继续往下看函数mapFrameBufferLocked:
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
- uint64_t refreshQuotient =
- (
- uint64_t( info.upper_margin + info.lower_margin + info.yres )
- * ( info.left_margin + info.right_margin + info.xres )
- * info.pixclock
- );
- /* Beware, info.pixclock might be 0 under emulation, so avoid a
- * division-by-0 here (SIGFPE on ARM) */
- int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;
- if (refreshRate == 0) {
- // bleagh, bad info from the driver
- refreshRate = 60*1000; // 60 Hz
- }
更多相关文章
- Android之Activity之间的数据通信方式大全(一)
- Android(安卓)Alert Dialog解决点击按钮对话框不关闭/的问题
- Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原
- 从实际问题中分析 Android中@id与@+id区别
- 个人使用的Android(安卓)Studio快捷键(MAC版)
- Facebook Fresco体验 (一)
- ubuntu android 命令环境下操作sqlite
- adb shell提示不是内部或外部命令
- Android(安卓)source build/envsetup.sh学习笔记