一、确认/dev/fb0
文件存在
在Ubuntu上画图,需要对应的FrameBuffer设备文件的支持,一般FrameBuffer的设备文件路径为/dev/fb开头的,可能是/dev/fb0或/dev/fb1等,所以进行下面的步骤之前要先确保/dev/fb*的文件是否存在。
如果你的Ubuntu版本比较旧,没有/dev/fb0的设备文件的话,可以参照这个文章:虚拟机的 Ubuntu 没有 /dev/fb0 的解决办法
二、Ubuntu进入命令行模式
Ubuntu有命令行模式和图形界面模式l,在图形界面模式时,即使执行了在/dev/fb0画图的程序也无法看到效果,所以执行FrameBuffer画图程序时,需要进入命令行。
可以通过按快捷键 Ctrl + Alt + F1来切换到命令行模式,通过按Ctrl + Alt + F7切换到图形界面模式。切换到命令行模式也可以Ctrl + Alt + (F1~F6任意一个)去切换。
三、在命令行模式下,执行FrameBuffer画图程序。
如果你自己有已经写好的FrameBuffer程序,经过前面两个步骤,应该可以执行跑起来了看到画图的效果了。运行程序时,需要加sudo,不然没有权限打开设备文件。如果没有程序或者跑起来有问题,可以复制下面代码编译执行,执行结果就是在左上角画一个30*30的方块,每秒变一个颜色,如图:
// framebuffer.c #include <stdio.h> #include <linux/fb.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> unsigned int fb_byteW=0, fb_byteH=0; // 用字节表示的宽度和高度 unsigned int bytesPerPixel = 0; // 一个像素占用的字节数 char *fbMapMem = NULL; void fillRect(int color, int x, int y, int w, int h) { int i=0, j=0, offset = 0; if(bytesPerPixel==4) { for(i=0; i<h; i++) { offset = x*bytesPerPixel + (y+i)*fb_byteW; for(j=0; j<w; j++) { int *tmp = (int *)&fbMapMem[offset]; *tmp = color; offset += bytesPerPixel; } } } else printf("error bytesPerPixel=%d\n", bytesPerPixel); } int main(int argc, char *argv[]) { // 1.打开设备 char fbPath[64] = "/dev/fb0"; int framebuf_fd = open(fbPath, O_RDWR); if ( framebuf_fd < 0 ) { printf("[%s:%d] open %s error \n", __FILE__,__LINE__,fbPath); return -1; } // 2.获取设备固定参数 struct fb_fix_screeninfo finfo; if (ioctl(framebuf_fd, FBIOGET_FSCREENINFO, &finfo) < 0) { fprintf(stderr, "ioctl FBIOGET_FSCREENINFO err \r\n"); return -1; } // 3.1 获取虚拟参数 struct fb_var_screeninfo vinfo; if (ioctl(framebuf_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) { fprintf(stderr, "ioctl FBIOGET_VSCREENINFO err \r\n"); return -1; } // 3.2 设置虚拟参数 bytesPerPixel = vinfo.bits_per_pixel / 8; vinfo.xres = vinfo.xres_virtual = finfo.line_length/bytesPerPixel; if (ioctl(framebuf_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0) { fprintf(stderr, "ioctl FBIOPUT_VSCREENINFO err \r\n"); return -1; } fb_byteW = vinfo.xres * bytesPerPixel; fb_byteH = vinfo.yres * bytesPerPixel; printf("[line:%d] line_length=%d res=[%dx%d], Bpp=%d ByteWH=[%d %d]\n",__LINE__,finfo.line_length,vinfo.xres,vinfo.yres,bytesPerPixel,fb_byteW, fb_byteH); // 4.映射物理显存到用户虚拟内存空间 unsigned long size = vinfo.xres*vinfo.yres*bytesPerPixel; if (NULL == (fbMapMem=(char *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, framebuf_fd, 0)) ) { fprintf(stderr, "mmap size %ld err \r\n", size); return -1; } // 5.操作虚拟内存,完成具体绘制任务,每隔一秒画一个颜色的正方形 while(1) { fillRect(0xff0000,0,0,30,30);// 红色 sleep(1); fillRect(0x00ff00,0,0,30,30);// 绿色 sleep(1); fillRect(0x0000ff,0,0,30,30);// 蓝色 sleep(1); } // 6.解除显存映射 munmap(fbMapMem, size); // 7.关闭设备 close(framebuf_fd); return 0; }
四、虚拟机Ubuntu的FrameBuffer(/dev/fb0
)画图的问题
如果你执行画图程序后,能出来东西,但画出来的图不是自己想要的,感觉分辨率没对应上,像下图一样。
原因可能就是设备固定参数(struct fb_fix_screeninfo)的line_length字段字节数,跟虚拟参数(struct fb_var_screeninfo)的分辨率的宽xres字段对不上。需要在你的程序里添加这句代码,再设置虚拟参数,可以参考上面代码。
vinfo.xres = vinfo.xres_virtual = finfo.line_length/bytesPerPixel;