Linux FrameBuffer分析之编写基于FrameBuffer接口的应用程序
作者:刘昊昱
博客:http://blog.csdn.net/liuhaoyutz
测试环境:Ubuntu 12.04终端模式
在网上找到一个很不错的介绍FrameBuffer相关知识的帖子,原帖网址如下:http://bbs.chinaunix.net/thread-1932291-1-1.html,现把其中测试FrameBuffer的应用程序代码转帖过来,方便分析学习:
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <linux/fb.h> #include <linux/kd.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <sys/time.h> #include <string.h> #include <errno.h> struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; char *frameBuffer = 0; //打印fb驱动中fix结构信息,注:在fb驱动加载后,fix结构不可被修改。 void printFixedInfo () { printf ("Fixed screen info:\n" "\tid: %s\n" "\tsmem_start:0x%lx\n" "\tsmem_len:%d\n" "\ttype:%d\n" "\ttype_aux:%d\n" "\tvisual:%d\n" "\txpanstep:%d\n" "\typanstep:%d\n" "\tywrapstep:%d\n" "\tline_length: %d\n" "\tmmio_start:0x%lx\n" "\tmmio_len:%d\n" "\taccel:%d\n" "\n", finfo.id, finfo.smem_start, finfo.smem_len, finfo.type, finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep, finfo.ywrapstep, finfo.line_length, finfo.mmio_start, finfo.mmio_len, finfo.accel); } //打印fb驱动中var结构信息,注:fb驱动加载后,var结构可根据实际需要被重置 void printVariableInfo () { printf ("Variable screen info:\n" "\txres:%d\n" "\tyres:%d\n" "\txres_virtual:%d\n" "\tyres_virtual:%d\n" "\tyoffset:%d\n" "\txoffset:%d\n" "\tbits_per_pixel:%d\n" "\tgrayscale:%d\n" "\tred: offset:%2d, length: %2d, msb_right: %2d\n" "\tgreen: offset:%2d, length: %2d, msb_right: %2d\n" "\tblue: offset:%2d, length: %2d, msb_right: %2d\n" "\ttransp: offset:%2d, length: %2d, msb_right: %2d\n" "\tnonstd:%d\n" "\tactivate:%d\n" "\theight:%d\n" "\twidth:%d\n" "\taccel_flags:0x%x\n" "\tpixclock:%d\n" "\tleft_margin:%d\n" "\tright_margin: %d\n" "\tupper_margin:%d\n" "\tlower_margin:%d\n" "\thsync_len:%d\n" "\tvsync_len:%d\n" "\tsync:%d\n" "\tvmode:%d\n" "\n", vinfo.xres, vinfo.yres, vinfo.xres_virtual, vinfo.yres_virtual, vinfo.xoffset, vinfo.yoffset, vinfo.bits_per_pixel, vinfo.grayscale, vinfo.red.offset, vinfo.red.length, vinfo.red.msb_right,vinfo.green.offset, vinfo.green.length, vinfo.green.msb_right, vinfo.blue.offset, vinfo.blue.length, vinfo.blue.msb_right, vinfo.transp.offset, vinfo.transp.length, vinfo.transp.msb_right, vinfo.nonstd, vinfo.activate, vinfo.height, vinfo.width, vinfo.accel_flags, vinfo.pixclock, vinfo.left_margin, vinfo.right_margin, vinfo.upper_margin, vinfo.lower_margin, vinfo.hsync_len, vinfo.vsync_len, vinfo.sync, vinfo.vmode); } //画大小为width*height的同色矩阵,8alpha+8reds+8greens+8blues void drawRect_rgb32 (int x0, int y0, int width,int height, int color) { const int bytesPerPixel = 4; const int stride = finfo.line_length / bytesPerPixel; int *dest = (int *) (frameBuffer) + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset); int x, y; for (y = 0; y < height; ++y) { for (x = 0; x < width; ++x) { dest[x] = color; } dest += stride; } } //画大小为width*height的同色矩阵,5reds+6greens+5blues void drawRect_rgb16 (int x0, int y0, int width,int height, int color) { const int bytesPerPixel = 2; const int stride = finfo.line_length / bytesPerPixel; const int red = (color & 0xff0000) >> (16 + 3); const int green = (color & 0xff00) >> (8 + 2); const int blue = (color & 0xff) >> 3; const short color16 = blue | (green << 5) | (red << (5 +6)); short *dest = (short *) (frameBuffer) + (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset); int x, y; for (y = 0; y < height; ++y) { for (x = 0; x < width; ++x) { dest[x] = color16; } dest += stride; } } //画大小为width*height的同色矩阵,5reds+5greens+5blues void drawRect_rgb15 (int x0, int y0, int width,int height, int color) { const int bytesPerPixel = 2; const int stride = finfo.line_length / bytesPerPixel; const int red = (color & 0xff0000) >> (16 + 3); const int green = (color & 0xff00) >> (8 + 3); const int blue = (color & 0xff) >> 3; const short color15 = blue | (green << 5) | (red << (5 + 5))| 0x8000; short *dest = (short *) (frameBuffer) + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset); int x, y; for (y = 0; y < height; ++y) { for (x = 0; x < width; ++x) { dest[x] = color15; } dest += stride; } } void drawRect (int x0, int y0, int width, intheight, int color) { switch (vinfo.bits_per_pixel) { case 32: drawRect_rgb32 (x0, y0, width, height, color); break; case 16: drawRect_rgb16 (x0, y0, width, height, color); break; case 15: drawRect_rgb15 (x0, y0, width, height, color); break; default: printf ("Warning: drawRect() not implemented for color depth%i\n", vinfo.bits_per_pixel); break; } } #define PERFORMANCE_RUN_COUNT 5 void performSpeedTest (void *fb, int fbSize) { int i, j, run; struct timeval startTime, endTime; unsigned long long results[PERFORMANCE_RUN_COUNT]; unsigned long long average; unsigned int *testImage; unsigned int randData[17] = { 0x3A428472, 0x724B84D3, 0x26B898AB,0x7D980E3C, 0x5345A084, 0x6779B66B, 0x791EE4B4, 0x6E8EE3CC, 0x63AF504A, 0x18A21B33, 0x0E26EB73, 0x022F708E, 0x1740F3B0, 0x7E2C699D, 0x0E8A570B, 0x5F2C22FB, 0x6A742130 }; printf ("Frame Buffer Performance test...\n"); for (run = 0; run < PERFORMANCE_RUN_COUNT; ++run) { /* Generate test image with random(ish) data: */ testImage = (unsigned int *) malloc (fbSize); j = run; for (i = 0; i < (int) (fbSize / sizeof (int)); ++i) { testImage[i] = randData[j]; j++; if (j >= 17) j = 0; } gettimeofday (&startTime, NULL); memcpy (fb, testImage, fbSize); gettimeofday (&endTime,NULL); long secsDiff = endTime.tv_sec - startTime.tv_sec; results[run] = secsDiff * 1000000 +(endTime.tv_usec - startTime.tv_usec); free (testImage); } average = 0; for (i = 0; i < PERFORMANCE_RUN_COUNT; ++i) average += results[i]; average = average / PERFORMANCE_RUN_COUNT; printf (" Average: %llu usecs\n", average); printf (" Bandwidth: %.03f MByte/Sec\n", (fbSize / 1048576.0) / ((double) average / 1000000.0)); printf (" Max. FPS: %.03f fps\n\n", 1000000.0 / (double) average); /* Clear the framebuffer back to black again: */ memset (fb, 0, fbSize); } int main (int argc, char **argv) { const char *devfile = "/dev/fb0"; long int screensize = 0; int fbFd = 0; /* Open the file for reading and writing */ fbFd = open (devfile, O_RDWR); if (fbFd == -1) { perror ("Error: cannot open framebuffer device"); exit (1); } //获取finfo信息并显示 if (ioctl (fbFd, FBIOGET_FSCREENINFO, &finfo) == -1) { perror ("Error reading fixed information"); exit (2); } printFixedInfo (); //获取vinfo信息并显示 if (ioctl (fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1) { perror ("Error reading variable information"); exit (3); } printVariableInfo (); /* Figure out the size of the screen in bytes */ screensize = finfo.smem_len; /* Map the device to memory */ frameBuffer = (char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbFd, 0); if (frameBuffer == MAP_FAILED) { perror ("Error: Failed to map framebuffer device to memory"); exit (4); } //测试virt fb的性能 performSpeedTest (frameBuffer, screensize); printf ("Will draw 3 rectangles on the screen,\n" "they should be coloredred, green and blue (in that order).\n"); drawRect (vinfo.xres / 8, vinfo.yres / 8, vinfo.xres / 4, vinfo.yres /4, 0xffff0000); drawRect (vinfo.xres * 3 / 8, vinfo.yres * 3 / 8, vinfo.xres / 4, vinfo.yres / 4,0xff00ff00); drawRect (vinfo.xres * 5 / 8, vinfo.yres * 5 / 8, vinfo.xres / 4, vinfo.yres /4, 0xff0000ff); sleep (5); printf (" Done.\n"); munmap (frameBuffer, screensize); //解除内存映射,与mmap对应 close (fbFd); return 0; }
该程序需要在打开FrameBuffer的终端模式下运行,我使用的Ubuntu 12.04,直接按Ctrl + Alt + F1,切换到终端1下,即可运行该程序。程序运行效果如下图所示:
说明一下,在终端模式下,截图软件我用的是fbgrab。
在我的电脑上,该程序在终端打印的信息如下:
Fixed screen info: id: inteldrmfb smem_start: 0xd0064000 smem_len: 8294400 type: 0 type_aux: 0 visual: 2 xpanstep: 1 ypanstep: 1 ywrapstep: 0 line_length: 7680 mmio_start: 0x0 mmio_len: 0 accel: 0 Variable screen info: xres: 1920 yres: 1080 xres_virtual: 1920 yres_virtual: 1080 yoffset: 0 xoffset: 0 bits_per_pixel: 32 grayscale: 0 red: offset: 16, length: 8,msb_right: 0 green: offset: 8, length: 8, msb_right: 0 blue: offset: 0, length: 8, msb_right: 0 transp: offset: 0, length: 0, msb_right: 0 nonstd: 0 activate: 0 height: -1 width: -1 accel_flags: 0x1 pixclock: 0 left_margin: 0 right_margin: 0 upper_margin: 0 lower_margin: 0 hsync_len: 0 vsync_len: 0 sync: 0 vmode: 0 Frame Buffer Performance test... Average: 1489 usecs Bandwidth: 5312.395 MByte/Sec Max.FPS: 671.592 fps Will draw 3 rectangles on the screen, they should be colored red, green and blue(in that order). Done.
通过这个测试程序,我们就能理解怎样在Linux用户空间,基于FrameBuffer接口,绘制想要的图形。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。