转自:https://www.jianshu.com/p/df1213e5a0ed

来自: Android技术特工队
作者: Aaron
主页: http://www.wxtlife.com/
原文连接:http://www.wxtlife.com/2017/06/07/Android-framebuffer/

如果想加入Android技术交流群,请长按识别二维码关注下方公众号,点击“加群”获取加群方式。

欢迎关注公众号:FutureCoder

FrameBuffer 介绍

FrameBuffer中文译名为帧缓冲驱动,它是出现在2.2.xx内核中的一种驱动程序接口。主设备号为29,次设备号递增。
Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。FrameBuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过FrameBuffer的读写直接对显存进行操作。用户可以将FrameBuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节,这些都是由FrameBuffer设备驱动来完成的。
FrameBuffer实际上就是嵌入式系统中专门为GPU所保留的一块连续的物理内存,LCD通过专门的总线从framebuffer读取数据,显示到屏幕上。
FrameBuffer本质上是一块显示缓存,往显示缓存中写入特定格式的数据就意味着向屏幕输出内容。所以说FrameBuffer就是一块白板。

屏幕位置从上到下,从左至右与内存地址是顺序的线性关系

FrameBuffer 使用

framebuffer的设备文件在Linux下一般是 /dev/fb0/dev/fb1 等,但在Android下面一般为/dev/graphics/fb0,/dev/graphics/fb1
注意: 系统中至少要存在一个显示屏,因此,名称为“fb0”的设备是肯定会存在的,否则的话,就是出错了。

操作framebuffer的主要步骤

1、打开可用的FrameBuffer设备;

    fbfd = open("/dev/graphics/fb0", O_RDWR);

O_RDWR是已可读写的方式打开文件

2、计算映射大小

用ioctrl操作取得当前显示屏幕的参数,如屏幕分辨率,每个像素点的比特数。根据屏幕参数可计算屏幕缓冲区的大小。

ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo); // fb_fix_screeninfo 通过fbfd获取屏幕固定的相关信息
ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo); // fb_var_screeninfo 通过fbfd获取可变的信息,可以调用参数为`FBIOPUT_VSCREENINFO`的重新进行设置

从fb_var_screeninfo中可以获取xoffset ,yoffset的偏移量,以及屏幕可见行列像素点(xres,yres),以及一个像素所占用的位数bits_per_pixel。
从fb_fix_screeninfo 中可以获取到framebuffer的内存空间大小finfo.smem_len,每行占用的字节数line_length等。

这些信息都是对我们下一步来计算需要映射多大的内存空间有很大的帮助,size 可以直接等于 finfo.smem_len, 或者 xres * yres * bits_per_pixel >> 3

3、通过mmap映射地址空间

通过mmap函数把显卡的物理内存空间映射到用户空间地址上

char *fbp = (char *)mmap(start, size, PROT_READ | PROT_WRITE, MAP_SHARED,fbfd, offsize);

各个参数的含义如下:

  • start 指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。
  • size 代表将文件中多大的部分映射到内存。
  • PROT_READ | PROT_WRITE 为可读可写模式
  • MAP_SHARED 对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
  • fbfd 要映射到内存中的文件描述符,也就是open文件后的描述符。
  • offsize 文件映射的偏移量

关于open、mmap的相关信息可以参考博客:http://www.wxtlife.com/2016/01/17/Android-memory-map/

4、更改内存空间里的像素数据并显示;

fbp则是映射framebuffer后的内存首地址,整个framebuffer的地址是线性的,与整个屏幕大小从左到右,从上到下映射的。所以操作framebuffer是按照每个像素去操作的,每个像素都需要计算他的偏移量也就是每个像素的内存地址空间.
例如在(x,y)位置写入颜色 pixel值。

4.1 首先先计算偏移量
offset = (x + y * screen_width) * 4; // (4个字节)

上面未考虑多buffer切换的地址空间的情况

4.2 给偏移量的内存地址赋值
*((uint32_t *)(fbp + offset)) = pixel;

5、退出时关闭framebuffer设备。

munmap(fbp, size);
close(fbfd);

size需要与mmap时一样,会导致内存泄露问题。
查看一个完整的示例demo :

int main() {
int fbfd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
char *fbp = 0;
long int location = 0;
// Open the file for reading and writing
fbfd = open("/dev/graphics/fb0", O_RDWR);
if (!fbfd) {
printf("Error: cannot open framebuffer device.\n");
exit(1);
}
printf("The framebuffer device was opened successfully.\n");
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
printf("Error reading fixed information.\n");
exit(2);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
printf("Error reading variable information.\n");
exit(3);
}
screensize = finfo.smem_len;
// screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel >> 3 // >>3 表示算出字节数
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,fbfd, 0); if ((int)fbp == -1) {
printf("Error: failed to map framebuffer device to memory.\n");
exit(4);
}

FrameBuffer 相关结构

FrameBuffer设备驱动基于如下两个文件:

  1. linux/include/linux/fb.h
  2. linux/drivers/video/fbmem.c

FrameBuffer 主要包含的结构有以下:fb_info ,fb_ops ,fb_var_screeninfo,fb_fix_screeninfo,上面的结构都定义在fb.h里。

fb_var_screeninfo

用于记录用户可修改的显示属性参数,包括屏幕分辨率、每个像素点的比特数等。
显卡的显示属性,用户可修改,此数据结构中,定义了偏移量(xoffset ,yoffset)、可见行列像素点(xres,yres)、每个像素所占bit位数(bits_per_pixel), 虚拟分辨率(xres_virtual、yres_virtual)在显存中包含的分辨率等信息,这些都是我们常见也是常用的到的。
这些数据我们是可以通过ioctl函数来获取,获取操作如下:ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) 。也可以重新进行赋值,之后再将设置进系统:设置如下:ioctl(fbfd, FBIOPUT_VSCREENINFO, &finfo)

数据结构如下:

struct fb_var_screeninfo {
__u32 xres; /* 行可见像素*/
__u32 yres; /* 列可见像素*/
__u32 xres_virtual; /* 行虚拟像素*/
__u32 yres_virtual; /* 列虚拟像素*/
__u32 xoffset; /* 水平偏移量*/
__u32 yoffset; /* 垂直偏移量*/
__u32 bits_per_pixel;/*每个像素所占bit位数*/
__u32 grayscale; /* 灰色刻度*/
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
__u32 nonstd; /* != 0 Non standard pixel format */
__u32 activate; /* see FB_ACTIVATE_* */
__u32 height; /* 图像高度*/
__u32 width; /* 图像宽度*/
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */
__u32 vsync_len; /* length of vertical sync */
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 reserved[5]; /* Reserved for future compatibility */
};

fb_fix_screeninfo

这个结构在显卡被设定模式后创建,它描述显示卡的属性,并且系统运行时不能被修改;比如FrameBuffer内存的起始地址。它依赖于被设定的模式,当一个模式被设定后,内存信息由显示卡硬件给出,内存的位置等信息就不可以修改。
显卡的硬件属性, 用户不可修改, 驱动程序初始化时设置。比如可以获取内存空间大小,起始地址,每行占用的字节数line_length等等。

数据结构如下:

struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start;/* Start of frame buffer mem */
__u32 smem_len; /* Length of frame buffer mem */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes */
unsigned long mmio_start;/* Start of Memory Mapped I/O */
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Indicate to driver which */
__u16 reserved[3]; /* Reserved for future compatibility */
};

fb_ops

是提供给底层设备驱动的一个接口,用户应用可以使用 ioctl() 系统调用来操作设备。

fb_cmap

描述设备无关的颜色映射信息。可以通过 FBIOGETCMAP 和 FBIOPUTCMAP 对应的 ioctl 操作设定或获取颜色映射信息。主要是颜色映射表,颜色相关一些映射信息。

fb_info

结构仅在内核中可见,在这个结构中有一个fb_ops指针,指向驱动设备工作所需的函数集,是Linux为帧缓冲设备定义的驱动层接口。它不仅包含了底层函数,而且还有记录设备状态的数据。每个帧缓冲设备都与一个fb_info结构相对应。

结构如下:

 
FrameBuffer结构图

ioctl中request参数:

  • FBIOGET_VSCREENINFO 表示用户获取屏幕的可变参数;
  • FBIOPUT_VSCREENINFO 表示用户设置可变的屏幕参数;
  • FBIOGET_FSCREENINFO 表示用户获得屏幕的固定参数;
  • FBIOBLANK表示调用sep4020fb_blank函数清空液晶屏;
  • FBIOPUTCMAP 表示设置屏幕的颜色表;
  • FBIOGETCMAP 表示获得颜色表。

双缓冲机制

Android 使用SurfaceFlinger作为屏幕合成引擎。它管理来自各个窗口的Surface objects,然后将其写入到framebuffer去。SurfaceFlinger使用前buffer来合成,后buffer来绘制。一旦绘制完成,Android通过页翻转操作,交换Y轴坐标的偏移量,选择不同buffer。在EGL显示服务初始化时,如果虚拟Y轴分辨率大于实际Y轴分辨率,说明framebuffer可以直接使用双缓冲。否则,后buffer要复制到前buffer,这样会导致页交换延迟。为了提高系统性能,Framebuffer驱动最好提供双缓冲机制。

双缓冲机制的原理

所有画图操作将它们画图的结果保存在一块系统内存区域中,这块区域通常被称作“后缓冲区(backbuffer)”,当所有的绘图操作结束之后,系统通过换页机制将绘制区域指向先前的后缓冲区,然后进行绘制显示,而原来的绘制缓冲区就变为“后缓冲区”,之后按照这种情况不停循环切换。这个复制操作通常要跟显示器的光栈束同步,以避免撕裂。双缓冲机制必须要求有比单缓冲更多的显示内存和CPU消耗时间,因为“后缓冲区”需要显示内存,而复制操作和等待同步需要CPU时间。

FrameBuffer1

framebuffer2

双缓冲是一种画图技术,使用这种技术可以使得画图没有(至少是减少)闪烁、撕裂等不良效果,并减少等待时间。

缓冲区切换步骤:

  1. 把fb驱动的framebuffer通过mmap映射到应用空间的内存地址map_base,一般来说framebuffer size是2*framesize或者3*framesize 大小(和平台相关)
  2. 把第一帧数据写入map_base
  3. 调用FBIOPAN_DISPLAY显示
  4. 把第二帧数据写入map_base+framesize处
  5. 调用FBIOPAN_DISPLAY
  6. 重复step2~step5

FBIOPAN_DISPLAY 在linux的注释里是“平移显示”的意思,调用FBIOPAN_DISPLAY时,会传一个y坐标偏移量yoffset给驱动,然后驱动会把当前显存的指针偏移 “yoffset X 屏幕宽度 X 位色字节数” 个字节,这样就好像实现了图像的y坐标平移,也就是“平移显示”。当这个yoffset等于屏幕高度的时候,就实现了显存的切换。

参考链接

http://www.cnblogs.com/armlinux/archive/2012/02/25/2396760.html
http://blog.csdn.net/yangwen123/article/details/12096483

如果想加入Android技术交流群,请长按识别二维码关注下方公众号,点击“加群”获取加群方式。

作者:技术特工队
链接:https://www.jianshu.com/p/df1213e5a0ed
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Android Framebuffer介绍及使用【转】的更多相关文章

  1. android Animation介绍

    Animation介绍: 在Android SDK介绍了2种Animation模式: 1. Tween Animation:间动画,通过对场景里的对象不断做图像变换(平移.缩放.旋转)产生动画效果,即 ...

  2. android AsyncTask介绍(转)

    android AsyncTask介绍 AsyncTask和Handler对比 1 ) AsyncTask实现的原理,和适用的优缺点 AsyncTask,是android提供的轻量级的异步类,可以直接 ...

  3. Android monkey介绍

    Android monkey介绍 原文地址 1 简略 monkey是android下自动化测试比较重要的的一个工具,该工具可以运行在host端或者设备(模拟器或真实设备).它会向系统发送随机事件流(即 ...

  4. [Learn Android Studio 汉化教程]第一章 : Android Studio 介绍

    注:为了看上去比较清晰这里只转载了中文 原地址:  [Learn Android Studio 汉化教程]第一章 : Android Studio 介绍 本章将引导您完成安装和设置开发环境,然后你就可 ...

  5. 【转】Android bluetooth介绍(三): 蓝牙扫描(scan)设备分析

    原文网址:http://blog.csdn.net/xubin341719/article/details/38584469 关键词:蓝牙blueZ  A2DP.SINK.sink_connect.s ...

  6. Android bluetooth介绍(四): a2dp connect流程分析

    关键词:蓝牙blueZ  A2DP.SINK.sink_connect.sink_disconnect.sink_suspend.sink_resume.sink_is_connected.sink_ ...

  7. android动画介绍之 自己定义Animation动画实现qq抖一抖效果

    昨天我们介绍了Animation的基本使用方法.小伙伴们了解的怎么样了?假设还没有了解过Animation的小伙伴能够看看这篇博客 android动画介绍--Animation 实现loading动画 ...

  8. android动画介绍之 自定义Animation动画实现qq抖一抖效果

    昨天我们介绍了Animation的基本用法.小伙伴们了解的怎么样了?如果还没有了解过Animation的小伙伴可以看看这篇博客 android动画介绍--Animation 实现loading动画效果 ...

  9. android动画介绍--Animation 实现loading动画效果

    Animation的使用方法并不难.这里简单的介绍一下使用方法. 先看效果图: 效果还是不错的吧. 下面来看看使用方法. 动画效果是通过Animation来实现的,一共有四种,分别为: AlphaAn ...

随机推荐

  1. Linux服务器中安装python包管理工具pip

    pip是python的包管理工具,python的强大之处除了在于语法的简练,还有就是对众多的库支持了. 1.下载pip包管理工具 链接地址:https://pypi.python.org/pypi/p ...

  2. 【BZOJ4006】管道连接(动态规划,斯坦纳树)

    题面 BZOJ 洛谷 题解 和这题区别不是很大吧. 基本上拿过来改一下就做完了. #include<iostream> #include<cstdio> #include< ...

  3. 【poj3294】 Life Forms

    http://poj.org/problem?id=3294 (题目链接) 题意 给定 n 个字符串,求出现在不小于 k 个字符串中的最长子串. Solution 后缀数组论文题.. 将 n 个字符串 ...

  4. MyBatis.2剖析

    上次给大家介绍了一下properties 和 environments 的配置, 接下来就正式开始看源码了: 上次例子中,我们以 SqlSessionFactoryBuilder 去创建 SqlSes ...

  5. 响应式开发(二)-----Bootstrap框架的介绍

    简介 Bootstrap,来自 Twitter,是目前最受欢迎的前端框架,是一个用于快速开发 Web 应用程序和网站的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的, ...

  6. CH暑假欢乐赛 SRM 07 天才麻将少女KPM(DP+treap)

    首先LIS有个$O(n^2)$的DP方法 $f(i,j)$表示前i个数,最后一个数<=j的LIS 如果$a_i!=0$则有 如果$a_i=0$则有 注意因为$f(i-1,j)\leq f(i-1 ...

  7. Java利用poi生成word(包含插入图片,动态表格,行合并)

    转(小改): Java利用poi生成word(包含插入图片,动态表格,行合并) 2018年12月20日 09:06:51 wjw_11093010 阅读数:70 Java利用poi生成word(包含插 ...

  8. bzoj 1503

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 12311  Solved: 4399[Submit][Stat ...

  9. [spark]-Spark2.x集群搭建与参数详解

    在前面的Spark发展历程和基本概念中介绍了Spark的一些基本概念,熟悉了这些基本概念对于集群的搭建是很有必要的.我们可以了解到每个参数配置的作用是什么.这里将详细介绍Spark集群搭建以及xml参 ...

  10. P4889 kls与flag

    P4889 kls与flag 一堆杆子, 每个有特定高度 \(a_{i}\) , 现想把杆子弄倒, 可以在一维内往左弄倒和往右弄倒, 求最大优秀对数, 定义优秀对数为两杆倒后顶点重合 Solution ...