Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析(7)

简介:
   显示屏的刷新频率与显示屏的扫描时序相关。显示屏的扫描时序可以参考Linux内核源代码目录下的Documentation/fb/framebuffer.txt文件。我们结合图2来简单说明上述代码是如何计算显示屏的刷新频率的。
图 2 显示屏扫描时序示意图
        中间由xres和yres组成的区域即为显示屏的图形绘制区,在绘制区的上、下、左和右分别有四个边距upper_margin、lower_margin、left_margin和right_margin。此外,在显示屏的最右边以及最下边还有一个水平同步区域hsync_len和一个垂直同步区域vsync_len。电子枪按照从左到右、从上到下的顺序来显示屏中打点,从而可以将要渲染的图形显示在屏幕中。前面所提到的区域信息分别保存在fb_var_screnninfo结构体info的成员变量xres、yres、upper_margin、lower_margin、left_margin、right_margin、hsync_len和vsync_len。
        电子枪每在xres和yres所组成的区域中打一个点所花费的时间记录在fb_var_screnninfo结构体info的成员变量pixclock,单位为pico seconds,即10E-12秒。 
        电子枪从左到右扫描完成一行之后,都会处理关闭状态,并且会重新折回到左边去。由于电子枪在从右到左折回的过程中不需要打点,因此,这个过程会比从左到右扫描屏幕的过程要快,这个折回的时间大概就等于在xres和yres所组成的区域扫描(left_margin+right_margin)个点的时间。这样,我们就可以认为每渲染一行需要的时间为(xres + left_margin + right_margin)* pixclock。
       同样,电子枪从上到下扫描完成显示屏之后,需要从右下角折回到左上角去,折回的时间大概等于在xres和yres所组成的区域中扫描(upper_margin + lower_margin)行所需要的时间。这样,我们就可以认为每渲染一屏图形所需要的时间等于在xres和yres所组成的区域中扫描(yres + upper_margin + lower_margin)行所需要的时间。由于在xres和yres所组成的区域中扫描一行所需要的时间为(xres + left_margin + right_margin)* pixclock,因此,每渲染一屏图形所需要的总时间就等于(yres + upper_margin + lower_margin)* (xres + left_margin + right_margin)* pixclock。
       每渲染一屏图形需要的总时间经过计算之后,就保存在变量refreshQuotient中。注意,变量refreshQuotient所描述的时间的单位为1E-12秒。这样,将变量refreshQuotient的值倒过来,就可以得到设备显示屏的刷新频率。将这个频率值乘以10E15次方之后,就得到一个单位为10E-3 HZ的刷新频率,保存在变量refreshRate中。
       当Android系统在模拟器运行的时候,保存在fb_var_screnninfo结构体info的成员变量pixclock中的值可能等于0。在这种情况下,前面计算得到的变量refreshRate的值就会等于0。在这种情况下,接下来的代码会将变量refreshRate的值设置为60 * 1000 * 10E-3 HZ,即将显示屏的刷新频率设置为60HZ。
       再往下看函数mapFrameBufferLocked:
  1. if (int(info.width) <= 0 || int(info.height) <= 0) {  
  2.     // the driver doesn't return that information  
  3.     // default to 160 dpi  
  4.     info.width  = ((info.xres * 25.4f)/160.0f + 0.5f);  
  5.     info.height = ((info.yres * 25.4f)/160.0f + 0.5f);  
  6. }  
  7.   
  8. float xdpi = (info.xres * 25.4f) / info.width;  
  9. float ydpi = (info.yres * 25.4f) / info.height;  
  10. float fps  = refreshRate / 1000.0f;  

        这段代码首先计算显示屏的密度,即每英寸有多少个像素点,分别宽度和高度两个维度,分别保存在变量xdpi和ydpi中。注意,fb_var_screeninfo结构体info的成员变量width和height用来描述显示屏的宽度和高度,它们是以毫米(mm)为单位的。
 
        这段代码接着再将前面计算得到的显示屏刷新频率的单位由10E-3 HZ转换为HZ,即帧每秒,并且保存在变量fps中。
        再往下看函数mapFrameBufferLocked:
  1. if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)  
  2.     return -errno;  
  3.   
  4. if (finfo.smem_len <= 0)  
  5.     return -errno;  
  6.   
  7.   
  8. module->flags = flags;  
  9. module->info = info;  
  10. module->finfo = finfo;  
  11. module->xdpi = xdpi;  
  12. module->ydpi = ydpi;  
  13. module->fps = fps;  
       这段代码再次通过IO控制命令FBIOGET_FSCREENINFO来获得系统帧缓冲区的固定信息,并且保存在fb_fix_screeninfo结构体finfo中,接下来再使用fb_fix_screeninfo结构体finfo以及前面得到的系统帧缓冲区的其它信息来初始化参数module所描述的一个private_module_t结构体。
 
       最后,函数mapFrameBufferLocked就将系统帧缓冲区映射到当前进程的地址空间来:
  1.     /* 
  2.      * map the framebuffer 
  3.      */  
  4.   
  5.     int err;  
  6.     size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);  
  7.     module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);  
  8.   
  9.     module->numBuffers = info.yres_virtual / info.yres;  
  10.     module->bufferMask = 0;  
  11.   
  12.     void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);  
  13.     if (vaddr == MAP_FAILED) {  
  14.         LOGE("Error mapping the framebuffer (%s)", strerror(errno));  
  15.         return -errno;  
  16.     }  
  17.     module->framebuffer->base = intptr_t(vaddr);  
  18.     memset(vaddr, 0, fbSize);  
  19.     return 0;  
  20. }  
        表达式finfo.line_length * info.yres_virtual计算的是整个系统帧缓冲区的大小,它的值等于显示屏行数(虚拟分辨率的高度值,info.yres_virtual)乘以每一行所占用的字节数(finfo.line_length)。函数roundUpToPageSize用来将整个系统帧缓冲区的大小对齐到页面边界。对齐后的大小保存在变量fbSize中。
 
        表达式finfo.yres_virtual / info.yres计算的是整个系统帧缓冲区可以划分为多少个图形缓冲区来使用,这个数值保存在参数module所描述的一个private_module_t结构体的成员变量nmBuffers中。参数module所描述的一个private_module_t结构体的另外一个成员变量bufferMask的值接着被设置为0,表示系统帧缓冲区中的所有图形缓冲区都是处于空闲状态,即它们可以分配出去给应用程序使用。
        系统帧缓冲区是通过调用函数mmap来映射到当前进程的地址空间来的。映射后得到的地址空间使用一个private_handle_t结构体来描述,这个结构体的成员变量base保存的即为系统帧缓冲区在当前进程的地址空间中的起始地址。这样,Gralloc模块以后就可以从这块地址空间中分配图形缓冲区给当前进程使用。
        至此,fb设备的打开过程就分析完成了。在打开fb设备的过程中,Gralloc模块还完成了对系统帧缓冲区的初始化工作。接下来我们继续分析Gralloc模块是如何分配图形缓冲区给用户空间的应用程序使用的。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/967084,如需转载请自行联系原作者
目录
相关文章
|
4月前
|
存储 编解码 网络协议
Android平台GB28181执法记录仪硬件选型和国标技术实现探讨
前几年,我们在做Android平台GB28181设备接入模块的时候,第一个使用场景想到的就是用在公检法应急指挥等场景下的执法记录仪,本篇blog,我们主要围绕Android平台GB28181执法记录仪的硬件选型、设备接入、音视频流配置、流媒体传输、存储和管理、控制与控制中心等方面进行设计,探讨下Android平台GB28181设备接入模块在执法记录仪行业的应用。
Android平台GB28181执法记录仪硬件选型和国标技术实现探讨
|
7月前
|
存储 Java Android开发
Android系统 设置第三方应用为默认Launcher实现和原理分析
Android系统 设置第三方应用为默认Launcher实现和原理分析
1039 0
|
4月前
|
缓存 API Android开发
Android经典实战之Kotlin Flow中的3个数据相关的操作符:debounce、buffer和conflate
本文介绍了Kotlin中`Flow`的`debounce`、`buffer`及`conflate`三个操作符。`debounce`过滤快速连续数据,仅保留指定时间内的最后一个;`buffer`引入缓存减轻背压;`conflate`仅保留最新数据。通过示例展示了如何在搜索输入和数据流处理中应用这些操作符以提高程序效率和用户体验。
54 6
|
7月前
|
安全 Android开发
Android HAL 层
Android HAL 层
54 1
|
7月前
|
安全 编译器 API
Android HAL深入探索(5): 调试HAL报错与解决方案
Android HAL深入探索(5): 调试HAL报错与解决方案
1303 1
|
7月前
|
传感器 Java Android开发
Android HAL深入探索(1): 架构概述
Android HAL深入探索(1): 架构概述
717 1
|
7月前
|
编解码 调度 Android开发
Android音频框架之一 详解audioPolicy流程及HAL驱动加载与配置
Android音频框架之一 详解audioPolicy流程及HAL驱动加载与配置
716 0
|
7月前
|
Java 物联网 Linux
Android硬件通信之 串口通信
Android硬件通信之 串口通信
117 0
|
7月前
|
Android开发 C++
Android S HAL库的编译
Android S HAL库的编译
76 0
|
7月前
|
Android开发 C++
Android P HAL层添加HIDL实例
Android P HAL层添加HIDL实例
119 0