1. FrameBuffer的介绍:
FrameBuffer,可以译作“帧缓冲”,有时简称为fbdrv。这是一种独立于硬件的抽象图形设备,是Linux为显示设备提供一个接口,把显示抽象后的一种设备,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作,即向应用层提供一个统一标准接口的显示设备。
用户无法通过用户内存空间向显存内存空间写入RGB颜色值,但可以通过内存映射单元,将用户空间的部分内存,映射到显存空间,实现RGB颜色值数据的写入,再通过显卡的转换在显示屏中显示。即通过内存映射技术,向显存中写入RGB颜色值,从而实现像素点的绘制。
2. FrameBuffer的使用:
控制fb,对于应用层,通过操作/dev/fb*,通过ioctl来用各种命令控制fb,可在linux系统中的/usr/include/linux/fb.h查看。
进入内核源码中看<linux/fb.h>,里面定义了一些ioctl的命令。
#define FBIOGET_VSCREENINFO 0x4600 //获取应用程序可改变的参数(如设定的分辨率)
#define FBIOPUT_VSCREENINFO 0x4601
#define FBIOGET_FSCREENINFO 0x4602 //获取固定的参数(如屏幕的分辨率,一般只是拿来看看)
#define FBIOGETCMAP 0x4604
#define FBIOPUTCMAP 0x4605
#define FBIOPAN_DISPLAY 0x4606
<linux/fb.h>中还提供了专门的结构体类型,用来存放上述两个参数,如下就是存放可变参数的结构体类型:
struct fb_var_screeninfo {
__u32 xres; /* visible resolution 可视画面的x、y轴分辨率 */
__u32 yres;
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible 可视画面相对于虚拟画面的x、y轴偏移量*/
__u32 yoffset; /* resolution */
__u32 bits_per_pixel; /* guess what 像素深度 */
__u32 grayscale; /* != 0 Graylevels instead of colors */
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; /* height of picture in mm */
__u32 width; /* width of picture in mm */
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
}
3. FrameBuffer用到的函数接口:
1. mmap:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
功能:内存映射
参数:
addr:欲映射内存的起始位置,NULL表示系统自动选定,映射成功后返回该地址。
length:映射内存大小
prot:映射区域的保护方式(读/写/执行/不能存取)
flags:影响区域映射的各种特性
MAP_SHARED:对映射区域写入的数据会复制回源文件内,而且允许其他映射该文件的进程共享。
MAP_PRIVATE:对映射区域的写入操作会产生一个映射文件的复制,即对此区域的任何修改都不会写回原来的文件内。
fd:要映射的目标文件
offset:文件映射的偏移量(0代表从开头开始)
返回值:
void *:返回映射欲映射内存的首地址
举例:
unsigned int* addr = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
2. munmap:
int munmap(void *addr, size_t length);
功能:解除内存映射
参数:
addr:映射内存的地址
length:映射内存大小
3.ioctl:
int ioctl(int fd, int request, ...);
功能:执行各种设备控制操作
参数:
fd:表示打开设备的文件描述符
request:是一个整数,表示对设备执行的操作类型或请求,这个参数指定了要执行的特定控制命令
...:表示可选的参数,具体取决于 'request' 参数的含义
举例:
ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); //获取屏幕信息(可变)
4. FrameBuffer的使用:
1. 初始化FrameBuffer:
#define RGB888_FMT 32
#define RGB565_FMT 16
int fb = 0;
size_t size = 0;
void *pmem = NULL;
struct fb_var_screeninfo vsinf;
int Init_FrameBuffer(const char *fbname)
{
fb = open(fbname, O_RDWR);
if(fb == -1)
{
perror("fail to open fb");
return -1;
}
int ret = ioctl(fb, FBIOGET_VSCREENINFO, &vsinf);
if(ret < 0)
{
perror("fail to ioctl");
return -1;
}
printf("xres: %d, yres: %d\n", vsinf.xres, vsinf.yres);
printf("xres_virtual: %d, yres_virtual: %d\n", vsinf.xres_virtual, vsinf.yres_virtual);
printf("bits_per_pixel: %d\n", vsinf.bits_per_pixel);
size = vsinf.xres_virtual * vsinf.yres_virtual * vsinf.bits_per_pixel / 8;
pmem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
if(pmem == (void *)-1)
{
perror("fail to mmap");
return -1;
}
return 0;
}
2. 绘制一个点:
void Draw_Point(int x, int y, unsigned int col)
{
if(x > vsinf.xres_virtual || y > vsinf.yres_virtual)
{
return;
}
if(vsinf.bits_per_pixel == RGB888_FMT)
{
unsigned int *p = pmem;
*(p + y * vsinf.xres_virtual + x) = col;
}
else if(vsinf.bits_per_pixel == RGB565_FMT)
{
unsigned short *p = pmem;
*(p + y * vsinf.xres_virtual + x) = col;
}
return;
}
3. 绘制一条横线:
void Draw_Transverse_Line(int x_begin, int x_end, int y, unsigned int col)
{
if(y > vsinf.yres_virtual || x_begin > vsinf.xres_virtual || x_end > vsinf.xres_virtual)
{
return;
}
if(vsinf.bits_per_pixel == RGB888_FMT)
{
unsigned int *p = pmem;
for(int i = x_begin; i <= x_end; i++)
{
*(p + y * vsinf.xres_virtual + i) = col;
}
}
else if(vsinf.bits_per_pixel == RGB565_FMT)
{
unsigned short *p = pmem;
for(int i = x_begin; i <= x_end; i++)
{
*(p + y * vsinf.xres_virtual + i) = col;
}
}
return;
}
4. 绘制一条竖线:
void Draw_Vertical_Line(int x, int y_begin, int y_end, unsigned int col)
{
if(x > vsinf.xres_virtual || y_begin > vsinf.yres_virtual || y_end > vsinf.yres_virtual)
{
return;
}
if(vsinf.bits_per_pixel == RGB888_FMT)
{
unsigned int *p = pmem;
for(int i = y_begin; i <= y_end; i++)
{
*(p + i * vsinf.xres_virtual + x) = col;
}
}
else if(vsinf.bits_per_pixel == RGB565_FMT)
{
unsigned short *p = pmem;
for(int i = y_begin; i <= y_end; i++)
{
*(p + i * vsinf.xres_virtual + x) = col;
}
}
return;
}
5. 绘制一个矩形:
void Draw_Rectangle(int x_begin, int y_begin, int x_end, int y_end, unsigned int col)
{
if(x_begin > vsinf.xres_virtual || y_begin > vsinf.yres_virtual || x_end > vsinf.xres_virtual || y_end > vsinf.yres_virtual)
{
return;
}
Draw_Transverse_Line(x_begin, x_end, y_begin, col);
Draw_Vertical_Line(x_begin, y_begin, y_end, col);
Draw_Transverse_Line(x_begin, x_end, y_end, col);
Draw_Vertical_Line(x_end, y_begin, y_end, col);
return;
}
6. 绘制一个圆:
void Draw_Circle(int x, int y, int R, unsigned int col)
{
if(x > vsinf.xres_virtual || y > vsinf.yres_virtual || x + R > vsinf.xres_virtual || y + R > vsinf.yres_virtual)
{
return;
}
if(vsinf.bits_per_pixel == RGB888_FMT)
{
int x0, y0;
for(float si = 0; si < 360; si += 0.1)
{
x0 = R * cos(2 * 3.1415926 / 360 * si) + x;
y0 = R * sin(2 * 3.1415926 / 360 * si) + y;
Draw_Point(x0, y0, col);
}
}
else if(vsinf.bits_per_pixel == RGB565_FMT)
{
int x0, y0;
for(float si = 0; si < 360; si += 0.1)
{
x0 = R * cos(2 * 3.1415926 / 360 * si) + x;
y0 = R * sin(2 * 3.1415926 / 360 * si) + y;
Draw_Point(x0, y0, col);
}
}
}
7. 显示一张bmp格式的图片:
void Draw_Bmp(const char *bmpname, int w, int h)
{
int fp = open(bmpname, O_RDONLY);
if(fp == -1)
{
perror("fail to open");
return;
}
lseek(fp, 54, SEEK_SET);
char *pbmp = malloc(w * h * 24 / 8);
if(pbmp == NULL)
{
perror("fail to malloc");
return;
}
read(fp, pbmp, w*h*24/8);
char *p = pbmp;
for(int j = h-1; j >= 0; j--)
{
for(int i = 0; i < w; i++)
{
unsigned char r, g, b;
b = *p; p++;
g = *p; p++;
r = *p; p++;
if(vsinf.bits_per_pixel == RGB888_FMT)
{
unsigned int col = r << 16 | g << 8 | b;
Draw_Point(i, j, col);
}
else if(vsinf.bits_per_pixel == RGB565_FMT)
{
unsigned short col = (r >> 3) << 11 | (g >> 2) << 5 | b;
Draw_Point(i, j, col);
}
}
}
free(pbmp);
close(fp);
return;
}
8. 清屏:
void Clear_Screen(void)
{
if(vsinf.bits_per_pixel == RGB888_FMT)
{
unsigned int *p = pmem;
for(int j = 0; j <= vsinf.yres_virtual; j++)
{
for(int i = 0; i <= vsinf.xres_virtual; i++)
{
*(p + j * vsinf.xres_virtual + i) = 0x00000000;
}
}
}
else if(vsinf.bits_per_pixel == RGB565_FMT)
{
unsigned int *p = pmem;
for(int j = 0; j <= vsinf.yres_virtual; j++)
{
for(int i = 0; i <= vsinf.xres_virtual; i++)
{
*(p + j * vsinf.xres_virtual + i) = 0x00000000;
}
}
}
return;
}
9. 关闭FrameBuffer:
void UnInit_FrameBuffer(void)
{
munmap(pmem, size);
close(fb);
return;
}