在Linux屏幕上画框和抛物线(framebuffer,mapped)

Framebuffer[1] 是用一个视频输出设备从包含完整的帧数据的一个内存缓冲区中来驱动一个视频显示设备。
在内存缓冲区中标准上包含了屏幕上每个像素的色彩值组成。色彩值通常存储成1-bit(黑白色彩),4-bit调色版,8-bit调色版,16-bit高色彩,24-bit真色彩格式。一个额外的alpha通道有时用来保存像素透明度信息。
帧缓冲设备提供了显卡的抽象描述。他同时代表了显卡上的显存,应用程序通过定义好的接口可以访问显卡,而不需要知道底层的任何操作。该设备使用特殊的设备节点,通常位于/dev目录,如/dev/fb0
*FrameBuffer的原理* 
FrameBuffer 是出现在 2.2.xx 内核当中的一种驱动程序接口。 
Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这 个设备来供用户态进程实现直接写屏。Framebuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过Framebuffer的读写直接对显存进行操 作。用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操 作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer设备驱动来完成的。 
    但Framebuffer本身不具备任何运算数据的能力,就只好比是一个暂时存放水的水池.CPU将运算后的结果放到这个水池,水池再将结果流到显示器.中间不会对数据做处理. 应用程序也可以直接读写这个水池的内容.在这种机制下,尽管Framebuffer需要真正的显卡驱动的支持,但所有显示任务都有CPU完成,因此CPU负担很重. 
framebuffer的设备文件一般是 /dev/fb0、/dev/fb1 等等。 
可以用命令: $ dd if=/dev/zero of=/dev/fb0 清空屏幕. 
如果显示模式是 1024x768-8 位色,用命令:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768 清空屏幕; 
用命令: $ dd if=/dev/fb0 of=fbfile  可以将fb中的内容保存下来; 
可以重新写回屏幕: #dd if=fbfile of=/dev/fb0; 
在使用Framebuffer时,Linux是将显卡置于图形模式下的. (ctrl+alt+f1(或者f2,f3,f4,f5,f6);恢复:ctrl+alt+f7)
将当前屏幕的内容复制到一个文件中:sudo  cp /dev/fb0  tmp
                           sudo  cat  /dev/fb0  >  tmp
将图形文件显示到文件中:sudo  cp  tmp  /dev/fb0
                   sudo  cat  tmp  >  /dev/fb0



 

  mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。munmap执行相反的操作,删除特定地址区域的对象映射。

当使用mmap映射文件到进程后,就可以直接操作这段虚拟地址进行文件的读写等操作,不必再调用read,write等系统调用.但需注意,直接对该段内存写时不会写入超过当前文件大小的内容.


#include <sys/mman.h>
void *mmap(void *start,  size_t length, int prot, int flags,  int fd, off_t offset);
int munmap(void *start,  size_t length);

参数说明编辑

start:映射区的开始地址,设置为0时表示由系统决定映射区的起始地址。
length:映射区的长度。//长度单位是 以字节为单位,不足一内存页按一内存页处理
prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起
PROT_EXEC //页内容可以被执行
PROT_READ //页内容可以被读取
PROT_WRITE //页可以被写入
PROT_NONE //页不可访问
flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体
MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者 munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
MAP_DENYWRITE //这个标志被忽略。
MAP_EXECUTABLE //同上
MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时 内存不足,对映射区的修改会引起段违例信号。
MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
MAP_GROWSDOWN //用于堆栈,告诉 内核VM系统,映射区可以向下扩展。
MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。
MAP_FILE //兼容标志,被忽略。
MAP_32BIT //将映射区放在进程 地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。
MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立 页表入口。
fd:有效的 文件描述词。一般是由open()函数返回,其值也可以设置为-1,此时需要指定flags参数中的MAP_ANON,表明进行的是匿名映射。
offset:被映射对象内容的起点。

4返回说明编辑

成功执行时,mmap()返回被映射区的 指针, munmap()返回0。失败时,mmap()返回MAP_FAILED[其值为(void *)-1], munmap返回-1。errno被设为以下的某个值
EACCES:访问出错
EAGAIN:文件已被锁定,或者太多的内存已被锁定
EBADF:fd不是有效的 文件描述词
EINVAL:一个或者多个参数无效
ENFILE:已达到系统对打开文件的限制
ENODEV:指定文件所在的文件系统不支持内存映射
ENOMEM: 内存不足,或者进程已超出最大内存映射数量
EPERM:权能不足,操作不允许
ETXTBSY:已写的方式打开文件,同时指定MAP_DENYWRITE标志
SIGSEGV:试着向只读区写入
SIGBUS:试着访问不属于进程的内存区


以下程序为在Linux图像界面打印输出方框和抛物线:


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>

#define FB0 "/dev/fb0"
#define FBSZ (640*480/8)

char *fa;

/*x表示列,y表示行,c为0(黑色)或1(白色)*/
int pset(int x, int y, int c)
{
	char *p = fa;
	int n;

	if(x<0 || x>=640 || y<0 || y>=480)
		return -1;

	n = y*640 + x;
	if(c){
		p[n/8] |= 1<<(7 - n%8);//一个位设置一个点,且从高位开始,p[0]用第7位设置,p[7]用第0位设置
	}
	else{
		p[n/8] &= ~(1<<(7 - n%8));
	}
	return 0;
}

int main(int argc, char *argv[])
{
	
	int fd;
	int i,j;
	float k;
	
	/*把数组与屏幕(framebuffer)联系起来*/
	fd = open(FB0,O_RDWR);
	fa = (char *)mmap(NULL, FBSZ, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(fa == MAP_FAILED){
		printf("map failed.\n");
		return -1;
	}
	
	for(i=0;i<FBSZ;i++)//清屏
        *(fa++)= 0x0;
		
	munmap(fa, FBSZ);
	
	fa = (char *)mmap(NULL, FBSZ, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(fa == MAP_FAILED){
		printf("map failed.\n");
		return -1;
	}
	
#if 1
	/*方框*/
	for(j=0;j<4;j++)//边框加粗
	{
		for(i=186; i<294; i++)//竖
		{
			pset(266+j, i, 1);
			pset(370+j, i, 1);
		}
			
		for(i=266; i<374; i++)//横
		{
			pset(i, 186+j, 1);
			pset(i, 290+j, 1);
		}	
	}
#endif

#if 1
	/*抛物线*/
	for(k= 0.005;k > 0.0048;k=k-0.00001)
		for(i=0;i<640;i++)
			pset(i,k*(i-320)*(i-320)+4,1);
#endif
	
	munmap(fa, FBSZ);
	close(fd);
	return 0;
}


运行结果:

在Linux屏幕上画框和抛物线(framebuffer,mapped)_第1张图片

你可能感兴趣的:(framebuffer,ARM-LINUX驱动学习)