framebuffer 帧缓冲

 Framebuffer(帧缓冲)是Linux系统中为显示设备提供的一套应用程序接口,它将显存抽象为一种设备,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。

        原理:通过内存映射技术向显存空间中写入rgb颜色值;

一、基本原理

        Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。 FrameBuffer机制模仿显卡的功能,将显卡硬件结构抽象掉, 可以通过FrameBuffer的读写直接对显存进行操作。 用户可以将FrameBuffer看成是显示内存的一个映像, 将其映射到进程地址空间之后,就可以直接进行读写操作, 而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。

二、使用基本步骤

步骤:

1.首先打开/dev/fb0设备文件

2.使用ioctl()函数获取当前显示设备的参数信息

3.使用存储映射I/O方式将屏幕的显示缓冲区映射到用户空间(mmap)

4映射成功后就可以直接读写屏幕的显示缓冲区,进行绘图和图片显示等操作

5.完成显示后,调用munmap()取消映射,并调用close()关闭设备文件。

三、相关函数

void *pmem;
struct fb_var_screeninfo vinf;
int init_fd(char *devname)
{
	//1. 打开显示设备
	int fd = open(devname, O_RDWR);	
	if (-1 == fd)
	{
		perror("fail open fb");
		return -1;
	}	
	//2、获取显示设备相关参数 分辨率 位深度
	int ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinf);
	if (-1 ==ret)
	{
		perror("fail ioctl");
		return -1;
	}
	printf("xres = %d, yres = %d\n", vinf.xres, vinf.yres);
	printf("xres_virtual = %d, yres_virtual = %d\n", vinf.xres_virtual, vinf.yres_virtual);
	printf("bits_per_pixel : %d\n", vinf.bits_per_pixel);
	size_t len = vinf.xres_virtual * vinf.yres_virtual * vinf.bits_per_pixel/8;
	//3, 建立显存和用户空间的映射关系
	pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if ((void *)-1 == pmem)
	{
		perror("fail mmap");
		return -1;
	}
	return fd;
}
  • 这一步操作是把设备的内存映射到用户空间里, 用户只需要对着这块内存操作就可以改变屏幕的内容, 与传统的write函数相比, 数据传输的速度以及便捷性都得到了大幅的提高

  • 第一行设置fb_mem为32位, 可以让我能够方便的使用32位的数据操作24位屏幕数据RGB888, 如果使用想要节省空间的话,可以使用unsigned char型, 不过颜色分量就需要解析,然后分别改写。

1
2
mmap的原型如下
caddr_t mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset);
  • 返回值为地址

  • addr :申请的地址,如果为空,系统会自动分配地址空间

  • len :申请内存空间的大小,单位为字节

  • prot :prot参数指定访问权限,可取如下几个值的“或”:PROT_READ(可读)、 PROT_WRITE(可写)、PROT_EXEC(可执行)和PROT_NONE(不可访问)

  • flags :两个参数可以选择:MAP_PRIVATE和MAP_SHARED 1. MAP_PRIVATE - 创建一个私人写时复制映射,映射的更新对映射相同文件的其他进程不可见,而且并不是通向底层文件。 2. MAP_SHARED - 分享该映射,映射的更新对映射此文件的其他进程可见,并被带到底层文件。

  • fd : 文件描述符,fd=-1,匿名映射

  • offset :映射文件的偏移量,从文件的哪里开始操作

四、绘制示例

void draw_point(int x,int y,unsigned int col)
{
	if(x >= vinf.xres || y >= vinf.yres)
	{
		return;
	}
	if(vinf.bits_per_pixel == RGB888_FMT)
	{
		unsigned int *p = pmem;
		*(p + y *vinf.xres_virtual + x ) = col;
	}
	else if(vinf.bits_per_pixel == RGB565_FMT)
	{
		unsigned short *p = pmem;
		*(p + y*vinf.xres_virtual + x) = col;
	}
	return;
}
void uninit_fb(int fd)
{
	size_t len = vinf.xres_virtual * vinf.yres_virtual * vinf.bits_per_pixel/8;
	munmap(pmem, len);
	close(fd);
}
void draw_hori_line(int x,int y,int len,unsigned int col)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		draw_point((x+i), y, col);
	}	
}
void draw_vert_line(int x,int y,int len,unsigned int col)
{
	int j = 0;
	for (j = 0; j < len; j++)
	{
		draw_point(x , (y+j), col);
	}	
}
void clear_screem(unsigned int col)
{
	int j = 0;
	int i = 0;
	for (j = 0; j < vinf.yres_virtual ; j++)
	{
		for(i = 0; i < vinf.xres_virtual ; ++i)
		{
			draw_point(i, j, col);
		}
	}	
}
void draw_rect(int x,int y,int high,int wieth,unsigned int col)
{
	draw_hori_line(x,y,wieth,col);
	draw_hori_line(x,(y+high),wieth,col);
	draw_vert_line(x,y,high,col);
    draw_vert_line((x + wieth), y, high, col);
}
void draw_circle(int x,int y,int r,unsigned int col)
{
	int x0 = 0;
    int y0 = 0;
    int d = 0;
    for (d = 0; d <= 360; d++)
    {
        x0 = r * cos(2 * 3.1415 / 360 * d) + x;
        y0 = r * sin(2 * 3.1415 / 360 * d) + y;
        draw_point(x0, y0, col);
    }
}
void draw_bias_line(int x,int y,int x1,int y1,unsigned col)
{
//	int x = 0;
//	int y = 0;
	if(x == x1)
	{
		if(y > y1)
		{
			draw_vert_line(x,y,y1-y,col);
		}
		else
		{
			draw_vert_line(x,y,y - y1,col);
		}
	}
	double k =(double) (y1 - y) /(double) (x1 - x);
	double b = (double) y1 - (k * x1);
	for( int i = 0; i < abs( x1 - x); ++i)
	{
	
		draw_point((int) x+i,(int) k *(x + i) + b,col);
	}
}
void draw_bmp(int x,int y,char *picture,int w,int h)
{
	int fd = open(picture,O_RDONLY);
	if(-1 == fd)
	{
		perror("fail open\n");
		return;
	}
	lseek(fd,54,SEEK_SET);
	unsigned char r,g,b;
	unsigned char *buff = malloc(w*h*3);
	read(fd,buff,w*h*3);
	unsigned char *p = buff;
	for(int j = h - 1 ; j >= 0; j-- )
	{
		for(int i = 0;i < w;i++)
		{
			b = *p; p++;
			g = *p; p++;
			r = *p; p++;
			if(vinf.bits_per_pixel == RGB888_FMT)
			{
				unsigned int col = (r << 16) | (g << 8) | (b << 0);
				draw_point(i + x, j + y,col);
			}
			else if(vinf.bits_per_pixel == RGB565_FMT)
			{
				unsigned short col = ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0);
				draw_point(i + x,j + y,col);
			}
		}
	}
}
/*void draw_word(int x,int y,unsigned char *zi,int w,int h,unsigned int col)
{
	for(int j = 0; j < h; j++)
	{
		for(int i = 0; i < w; i++)
		{
			unsigned char tmp = word[i+j*w];
			for(int k = 0;k < 8;++k)
			{
				if(tmp & 0x80)
				{
					draw_point(i*8+k+x,j+y,col);
				}
				else
				{
					draw_point(i*8+k+x,j+y,0x0000ffff);
				}
				tmp = tmp << 1;
			}
		}
	}
}*/
int display_show_utf8(UTF8_INFO *info, int x, int y, char* zi, u32 col, u32 col1)
{
    unsigned long  out = 0 ;
    int ret = enc_utf8_to_unicode_one((unsigned char*)zi,&out);
    unsigned char* data = get_utf_data(info,out);
    unsigned char temp = 0 ;
    unsigned int i,j,k;
    unsigned int num = 0;
    for(i=0;i<info->height;i++)
    {
        for(j=0;j<info->width/8;j++)
        {
            temp = data[num++];
            for(k=0;k<8;k++)
            {
                if(0x80&temp)
                {
                    draw_point( x+k+j*8, y+i, col);
                }
                else
                {
                 //   draw_point( x+k+j*8, y+i, col1);
                }
                temp= temp<<1;
            }
        }
    }
    return ret;
}
int display_show_utf8_str(UTF8_INFO *info, int arg_x, int arg_y,  char* zi, u32 col, u32 col1)
{
    char* temp = zi;
    unsigned int x = arg_x ;
    unsigned int y =  arg_y;

    while(*temp != '\0')
    {
        int ret = display_show_utf8(info, x, y, temp, col, col1);
        x += info->width;
        if(x > vinf.xres_virtual)
        {
            x = 0;
            y += info->height;
            if(y > vinf.yres_virtual)
            {
                y = 0;
            }
        }

        temp += ret;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值