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接口,绘制想要的图形。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux上,您可以使用framebuffer来显示字符打印。Framebuffer是一种在内存中维护图形缓冲区的设备,它可以直接访问和控制显示器的像素。 要通过应用程序使用framebuffer显示字符打印,您可以按照以下步骤进行操作: 1. 打开framebuffer设备:使用`open()`函数打开framebuffer设备文件。通常,framebuffer设备文件的路径是`/dev/fb0`。 2. 获取framebuffer信息:使用`ioctl()`函数和`FBIOGET_VSCREENINFO`命令来获取framebuffer的信息结构体。您可以使用`struct fb_var_screeninfo`类型的结构体来存储此信息。 3. 设置终端模式:如果您正在从终端登录并且需要在终端模式下显示字符打印,可以使用`ioctl()`函数和`KDSETMODE`命令将终端模式设置为`KD_GRAPHICS`。 4. 映射framebuffer内存:使用`mmap()`函数将framebuffer设备文件映射到内存中。您可以使用`struct fb_fix_screeninfo`类型的结构体来获取framebuffer内存地址和长度。 5. 编写字符打印代码:您可以使用映射的framebuffer内存地址来直接操作像素,从而实现字符打印。您可以选择使用ASCII表中的字符,并将它们绘制到适当的位置上。 6. 刷新屏幕:在完成字符打印后,使用`ioctl()`函数和`FBIO_REFRESH_RATE`命令来刷新屏幕。 7. 关闭framebuffer设备:最后,使用`close()`函数关闭framebuffer设备。 请注意,使用framebuffer直接操作像素是一种底层的方法,需要对图形编程和硬件进行一定的了解。此外,不同的嵌入式系统和显示设备可能有不同的framebuffer实现和操作方式。 以上是一个简单的概述,实际操作中可能需要更多的细节和代码。如果您想了解更多关于使用framebuffer显示字符打印的详细信息,建议查阅相关的文档或参考示例代码。 希望这些信息对您有所帮助!如有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值