Linux framebuffer显示bmp图片

  • Post author:
  • Post category:linux

帧缓冲(framebuffer)是Linux为显示设备提供的一个接口,把显存抽象后的一种设备,他允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。

  framebuffer是LCD对应的一种HAL(硬件抽象层),提供抽象的,统一的接口操作,用户不必关心硬件层是怎么实施的。这些都是由Framebuffer设备驱动来完成的。

  帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显示卡,Linux下还可支持多个帧缓冲设备,最多可达32个,分别为/dev/fb0到/dev/fb31,而/dev/fb则为当前缺省的帧缓冲设备,通常指向/dev/fb0,在嵌入式系统中支持一个显示设备就够了。帧缓冲设备为标准字符设备,主设备号为29,次设备号则从0到31,分别对应/dev/fb0-/dev/fb31。

  通过/dev/fb,应用程序的操作主要有这几种:

  • 读/写(read/write)/dev/fb:相当于读/写屏幕缓冲区。
  • 映射(map)操作:由于Linux工作在保护模式,每个应用程序都有自己的虚拟地址空间,在应用程序中是不能直接访问物理缓冲区地址的。而帧缓冲设备可以通过mmap()映射操作将屏幕缓冲区的物理地址映射到用户空间的一段虚拟地址上,然后用户就可以通过读写这段虚拟地址访问屏幕缓冲区,在屏幕上绘图了。
  • I/O控制:对于帧缓冲设备,对设备文件的ioctl操作可读取/设置显示设备及屏幕的参数,如分辨率,屏幕大小等相关参数。ioctl的操作是由底层的驱动程序来完成的。

  在应用程序中,操作/dev/fb的一般步骤如下: 
1. 打开/dev/fb设备文件。 
2. 用ioctl操作取得当前显示屏幕的参数,根据屏幕参数可计算屏幕缓冲区的大小。 
3. 将屏幕缓冲区映射到用户空间。 
4. 映射后即可直接读写屏幕缓冲区,进行绘图和图片显示。

  framebuffer相关数据结构介绍

  • fb_info结构体:帧缓冲设备中最重要的数据结构体,包括了帧缓冲设备属性和操作的完整性属性。定义显卡的当前状态;fb_info结构仅在内核中可见,在这个结构中有一个fb_ops指针。
  • fb_ops结构体:fb_info结构体的成员变量,fb_ops为指向底层操作的函数的指针。
  • fb_var_screen和fb_fix_screen结构体:fb_var_screen记录用户可以修改的显示控制器参数,之所以可以修改,是因为对同样的图形硬件,可以工作在不同的模式下。简单来讲,一个支持1024x768x24图形模式的硬件通常也能工作在800x600x16的图形模式下。可变的信息就是指Framebuffer的长度、宽度以及颜色深度等信息。
  • fb_fix_screen记录用户不能修改的显示控制器参数。比如图形硬件上实际的帧缓存空间的大小、能否硬件加速等信息。

  应用程序中通常要用到struct fb_var_screeninfo的下面这几个字段: 
  xres、yres、bits_per_pixel,分别表示x轴的分辨率、y轴的分辨率以及每像素的颜色深度(颜色深度的单位为bit/pixel),其类型定义都是无符号32位整型数。

<span style="color:#000000"><code class="language-C"><span style="color:#009900">#include <unistd.h></span>
<span style="color:#009900">#include <stdio.h></span>
<span style="color:#009900">#include <stdlib.h></span>
<span style="color:#009900">#include <fcntl.h></span>
<span style="color:#009900">#include <string.h></span>
<span style="color:#009900">#include <linux/fb.h></span>
<span style="color:#009900">#include <sys/mman.h></span>
<span style="color:#009900">#include <sys/ioctl.h></span>
<span style="color:#009900">#include <arpa/inet.h></span>
<span style="color:#009900">#include <errno.h></span>

<span style="color:#880000">//14byte文件头</span>
<span style="color:#000088">typedef</span> <span style="color:#000088">struct</span>
{
    <span style="color:#000088">char</span>    cfType[<span style="color:#006666">2</span>];<span style="color:#880000">//文件类型,"BM"(0x4D42)</span>
    <span style="color:#000088">int</span>     cfSize;<span style="color:#880000">//文件大小(字节)</span>
    <span style="color:#000088">int</span> cfReserved;<span style="color:#880000">//保留,值为0</span>
    <span style="color:#000088">int</span>     cfoffBits;<span style="color:#880000">//数据区相对于文件头的偏移量(字节)</span>
}__attribute__((packed)) BITMAPFILEHEADER;
<span style="color:#880000">//__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐</span>

<span style="color:#880000">//40byte信息头</span>
<span style="color:#000088">typedef</span> <span style="color:#000088">struct</span>
{
    <span style="color:#000088">char</span> ciSize[<span style="color:#006666">4</span>];<span style="color:#880000">//BITMAPFILEHEADER所占的字节数</span>
    <span style="color:#000088">int</span>  ciWidth;<span style="color:#880000">//宽度</span>
    <span style="color:#000088">int</span>  ciHeight;<span style="color:#880000">//高度</span>
    <span style="color:#000088">char</span> ciPlanes[<span style="color:#006666">2</span>];<span style="color:#880000">//目标设备的位平面数,值为1</span>
    <span style="color:#000088">int</span>  ciBitCount;<span style="color:#880000">//每个像素的位数</span>
    <span style="color:#000088">char</span> ciCompress[<span style="color:#006666">4</span>];<span style="color:#880000">//压缩说明</span>
    <span style="color:#000088">char</span> ciSizeImage[<span style="color:#006666">4</span>];<span style="color:#880000">//用字节表示的图像大小,该数据必须是4的倍数</span>
    <span style="color:#000088">char</span> ciXPelsPerMeter[<span style="color:#006666">4</span>];<span style="color:#880000">//目标设备的水平像素数/米</span>
    <span style="color:#000088">char</span> ciYPelsPerMeter[<span style="color:#006666">4</span>];<span style="color:#880000">//目标设备的垂直像素数/米</span>
    <span style="color:#000088">char</span> ciClrUsed[<span style="color:#006666">4</span>]; <span style="color:#880000">//位图使用调色板的颜色数</span>
    <span style="color:#000088">char</span> ciClrImportant[<span style="color:#006666">4</span>]; <span style="color:#880000">//指定重要的颜色数,当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要</span>
}__attribute__((packed)) BITMAPINFOHEADER;

<span style="color:#000088">typedef</span> <span style="color:#000088">struct</span>
{
    <span style="color:#000088">unsigned</span> <span style="color:#000088">char</span> blue;
    <span style="color:#000088">unsigned</span> <span style="color:#000088">char</span> green;
    <span style="color:#000088">unsigned</span> <span style="color:#000088">char</span> red;
    <span style="color:#000088">unsigned</span> <span style="color:#000088">char</span> reserved;
}__attribute__((packed)) PIXEL;<span style="color:#880000">//颜色模式RGB</span>

BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;

<span style="color:#000088">static</span> <span style="color:#000088">char</span> *fbp = <span style="color:#006666">0</span>;
<span style="color:#000088">static</span> <span style="color:#000088">int</span> xres = <span style="color:#006666">0</span>;
<span style="color:#000088">static</span> <span style="color:#000088">int</span> yres = <span style="color:#006666">0</span>;
<span style="color:#000088">static</span> <span style="color:#000088">int</span> bits_per_pixel = <span style="color:#006666">0</span>;
<span style="color:#000088">int</span> width, height;

<span style="color:#000088">int</span> show_bmp();
<span style="color:#000088">int</span> fbfd = <span style="color:#006666">0</span>;

<span style="color:#000088">static</span> <span style="color:#000088">void</span> fb_update(<span style="color:#000088">struct</span> fb_var_screeninfo *vi)   <span style="color:#880000">//将要渲染的图形缓冲区的内容绘制到设备显示屏来</span>
{  
    vi->yoffset = <span style="color:#006666">1</span>;  
    ioctl(fbfd, FBIOPUT_VSCREENINFO, vi);  
    vi->yoffset = <span style="color:#006666">0</span>;  
    ioctl(fbfd, FBIOPUT_VSCREENINFO, vi);  
}  

<span style="color:#000088">static</span> <span style="color:#000088">int</span> cursor_bitmap_format_convert(<span style="color:#000088">char</span> *dst,<span style="color:#000088">char</span> *src)
{
    <span style="color:#000088">int</span> i ,j ;
    <span style="color:#000088">char</span> *psrc = src ;
    <span style="color:#000088">char</span> *pdst = dst;
    <span style="color:#000088">char</span> *p = psrc;

    <span style="color:#880000">/* 由于bmp存储是从后面往前面,所以需要倒序进行转换 */</span>
    pdst += (width * height * <span style="color:#006666">3</span>);
    <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>;i<height;i++){
        p = psrc + (i+<span style="color:#006666">1</span>) * width * <span style="color:#006666">3</span>;
        <span style="color:#000088">for</span>(j=<span style="color:#006666">0</span>;j<width;j++){
            pdst -= <span style="color:#006666">3</span>;
            p -= <span style="color:#006666">3</span>;
            pdst[<span style="color:#006666">0</span>] = p[<span style="color:#006666">0</span>];
            pdst[<span style="color:#006666">1</span>] = p[<span style="color:#006666">1</span>];
            pdst[<span style="color:#006666">2</span>] = p[<span style="color:#006666">2</span>];
        }
    }
    <span style="color:#000088">return</span> <span style="color:#006666">0</span>;
}

<span style="color:#000088">int</span> show_bmp(<span style="color:#000088">char</span> *path)
{
    <span style="color:#000088">int</span> i;
    FILE *fp;
    <span style="color:#000088">int</span> rc;
    <span style="color:#000088">int</span> line_x, line_y;
    <span style="color:#000088">long</span> <span style="color:#000088">int</span> location = <span style="color:#006666">0</span>, BytesPerLine = <span style="color:#006666">0</span>;
    <span style="color:#000088">char</span> *bmp_buf = NULL;
    <span style="color:#000088">char</span> *bmp_buf_dst = NULL;
    <span style="color:#000088">char</span> * buf = NULL;
    <span style="color:#000088">int</span> flen = <span style="color:#006666">0</span>;
    <span style="color:#000088">int</span> ret = -<span style="color:#006666">1</span>;
    <span style="color:#000088">int</span> total_length = <span style="color:#006666">0</span>;

    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"into show_bmp function\n"</span>);
    <span style="color:#000088">if</span>(path == NULL)
    {
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"path Error,return\n"</span>);
        <span style="color:#000088">return</span> -<span style="color:#006666">1</span>;
    }
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"path = %s\n"</span>, path);
    fp = fopen( path, <span style="color:#009900">"rb"</span> );
    <span style="color:#000088">if</span>(fp == NULL){
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"load cursor file open failed\n"</span>);
        <span style="color:#000088">return</span> -<span style="color:#006666">1</span>;
    }

    <span style="color:#880000">/* 求解文件长度 */</span>
    fseek(fp,<span style="color:#006666">0</span>,SEEK_SET);
    fseek(fp,<span style="color:#006666">0</span>,SEEK_END);

    flen = ftell(fp);
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"flen is %d\n"</span>,flen);

    bmp_buf = (<span style="color:#000088">char</span>*)<span style="color:#4f4f4f">calloc</span>(<span style="color:#006666">1</span>,flen - <span style="color:#006666">54</span>);
    <span style="color:#000088">if</span>(bmp_buf == NULL){
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"load > malloc bmp out of memory!\n"</span>);
        <span style="color:#000088">return</span> -<span style="color:#006666">1</span>;
    }

    <span style="color:#880000">/* 再移位到文件头部 */</span>
    fseek(fp,<span style="color:#006666">0</span>,SEEK_SET);

    rc = fread(&FileHead, <span style="color:#000088">sizeof</span>(BITMAPFILEHEADER),<span style="color:#006666">1</span>, fp);
    <span style="color:#000088">if</span> ( rc != <span style="color:#006666">1</span>)
    {
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"read header error!\n"</span>);
        fclose( fp );
        <span style="color:#000088">return</span>( -<span style="color:#006666">2</span> );
    }

    <span style="color:#880000">//检测是否是bmp图像</span>
    <span style="color:#000088">if</span> (<span style="color:#4f4f4f">memcmp</span>(FileHead.cfType, <span style="color:#009900">"BM"</span>, <span style="color:#006666">2</span>) != <span style="color:#006666">0</span>)
    {
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"it's not a BMP file\n"</span>);
        fclose( fp );
        <span style="color:#000088">return</span>( -<span style="color:#006666">3</span> );
    }
    rc = fread( (<span style="color:#000088">char</span> *)&InfoHead, <span style="color:#000088">sizeof</span>(BITMAPINFOHEADER),<span style="color:#006666">1</span>, fp );
    <span style="color:#000088">if</span> ( rc != <span style="color:#006666">1</span>)
    {
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"read infoheader error!\n"</span>);
        fclose( fp );
        <span style="color:#000088">return</span>( -<span style="color:#006666">4</span> );
    }
    width = InfoHead.ciWidth;
    height = InfoHead.ciHeight;

    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"FileHead.cfSize =%d byte\n"</span>,FileHead.cfSize);
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"flen = %d\n"</span>, flen);
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"width = %d, height = %d\n"</span>, width, height);

    total_length = width * height *<span style="color:#006666">3</span>;

    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"total_length = %d\n"</span>, total_length);

    <span style="color:#880000">//跳转的数据区</span>
    fseek(fp, FileHead.cfoffBits, SEEK_SET);
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">" FileHead.cfoffBits = %d\n"</span>,  FileHead.cfoffBits);
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">" InfoHead.ciBitCount = %d\n"</span>,  InfoHead.ciBitCount);    

    <span style="color:#880000">//每行字节数</span>
    buf = bmp_buf;
    <span style="color:#000088">while</span> ((ret = fread(buf,<span style="color:#006666">1</span>,total_length,fp)) >= <span style="color:#006666">0</span>) {
        <span style="color:#000088">if</span> (ret == <span style="color:#006666">0</span>) {
            usleep(<span style="color:#006666">100</span>);
            <span style="color:#000088">continue</span>;
        }
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"ret = %d\n"</span>, ret);
        buf = ((<span style="color:#000088">char</span>*) buf) + ret;
        total_length = total_length - ret;
        <span style="color:#000088">if</span>(total_length == <span style="color:#006666">0</span>)
            <span style="color:#000088">break</span>;
    }

    <span style="color:#880000">///重新计算,很重要!!</span>
    total_length = width * height *<span style="color:#006666">3</span>;
    bmp_buf_dst = (<span style="color:#000088">char</span>*)<span style="color:#4f4f4f">calloc</span>(<span style="color:#006666">1</span>,total_length );
    <span style="color:#000088">if</span>(bmp_buf_dst == NULL){
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"load > malloc bmp out of memory!\n"</span>);
        <span style="color:#000088">return</span> -<span style="color:#006666">1</span>;
    }

    cursor_bitmap_format_convert(bmp_buf_dst, bmp_buf);
    <span style="color:#4f4f4f">memcpy</span>(fbp,bmp_buf_dst,total_length);

    <span style="color:#4f4f4f">free</span>(bmp_buf);
    <span style="color:#4f4f4f">free</span>(bmp_buf_dst);

    fclose(fp);
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"show logo return 0\n"</span>);
    <span style="color:#000088">return</span> <span style="color:#006666">0</span>;
}

<span style="color:#000088">int</span> show_picture(<span style="color:#000088">int</span> fd, <span style="color:#000088">char</span> *path)
{
    <span style="color:#000088">struct</span> fb_var_screeninfo vinfo;
    <span style="color:#000088">struct</span> fb_fix_screeninfo finfo;
    <span style="color:#000088">long</span> <span style="color:#000088">int</span> screensize = <span style="color:#006666">0</span>;
    <span style="color:#000088">struct</span> fb_bitfield red;
    <span style="color:#000088">struct</span> fb_bitfield green;
    <span style="color:#000088">struct</span> fb_bitfield blue;

    <span style="color:#880000">//打开显示设备</span>
    fbfd = fd;          <span style="color:#880000">//open("/dev/graphics/fb0", O_RDWR);</span>
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"fbfd = %d\n"</span>, fbfd);
    <span style="color:#000088">if</span> (fbfd == -<span style="color:#006666">1</span>)
    {
        <span style="color:#880000">//printf("Error opening frame buffer errno=%d (%s)\n",errno, strerror(errno));</span>
        <span style="color:#000088">return</span> -<span style="color:#006666">1</span>;
    }

    <span style="color:#000088">if</span> (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
    {
        <span style="color:#880000">//printf("Error:reading fixed information.\n");</span>
        <span style="color:#000088">return</span> -<span style="color:#006666">1</span>;
    }

    <span style="color:#000088">if</span> (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
    {
        <span style="color:#880000">//printf("Error: reading variable information.\n");</span>
        <span style="color:#000088">return</span> -<span style="color:#006666">1</span>;
    }

    <span style="color:#880000">//printf("R:%x ;G:%d ;B:%d \n", (int)vinfo.red, vinfo.green, vinfo.blue );</span>
    <span style="color:#880000">//printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );</span>

    xres = vinfo.xres;
    yres = vinfo.yres;
    bits_per_pixel = vinfo.bits_per_pixel;

    <span style="color:#880000">//计算屏幕的总大小(字节)</span>
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / <span style="color:#006666">8</span>;
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"screensize=%ld byte\n"</span>,screensize);

    <span style="color:#880000">//对象映射</span>
    fbp = (<span style="color:#000088">char</span> *)mmap(<span style="color:#006666">0</span>, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, <span style="color:#006666">0</span>);
    <span style="color:#000088">if</span> (fbp == (<span style="color:#000088">char</span> *)-<span style="color:#006666">1</span>)
    {
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"Error: failed to map framebuffer device to memory.\n"</span>);
        <span style="color:#000088">return</span> -<span style="color:#006666">1</span>;
    }

    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"sizeof file header=%ld\n"</span>, <span style="color:#000088">sizeof</span>(BITMAPFILEHEADER));

    <span style="color:#880000">//显示图像</span>
    show_bmp(path);

    <span style="color:#880000">///在屏幕上显示多久</span>
    sleep(<span style="color:#006666">100</span>);

    fb_update(&vinfo);

    <span style="color:#880000">//删除对象映射</span>
    munmap(fbp, screensize);

    <span style="color:#000088">return</span> <span style="color:#006666">0</span>;
}

<span style="color:#000088">int</span> main()
{
    <span style="color:#000088">int</span> fbfd = <span style="color:#006666">0</span>;

    fbfd = open(<span style="color:#009900">"/dev/fb0"</span>, O_RDWR);  
    <span style="color:#000088">if</span> (!fbfd)  
    {  
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"Error: cannot open framebuffer device.\n"</span>);  
        <span style="color:#4f4f4f">exit</span>(<span style="color:#006666">1</span>);  
    } 
    show_picture(fbfd, <span style="color:#009900">"./girl.bmp"</span>);

    close(fbfd);
}</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280

  这里我们是使用qemu模拟的,否则用主机会打乱工作环境! 首先按照我以前博文: 
linux内核调试环境搭建搭建起来一个最小linux环境。

  注意到在编译内核的时候要加入一个内核配置选项,不然内核不支持 qemu 显卡设备,也就无法创建/dev/fb0 设备文件。

<span style="color:#000000"><code>CONFIG_DRM_CIRRUS_QEMU=<span style="color:#009900">y</span></code></span>
  • 1
<span style="color:#000000"><code>config DRM_CIRRUS_QEMU
    tristate <span style="color:#009900">"Cirrus driver for QEMU emulated device"</span>
    depends <span style="color:#000088">on</span> DRM && PCI
    <span style="color:#000088">select</span> FB_SYS_FILLRECT
    <span style="color:#000088">select</span> FB_SYS_COPYAREA
    <span style="color:#000088">select</span> FB_SYS_IMAGEBLIT
    <span style="color:#000088">select</span> DRM_KMS_HELPER
    <span style="color:#000088">select</span> DRM_KMS_FB_HELPER
    <span style="color:#000088">select</span> DRM_TTM
    help
     This <span style="color:#000088">is</span> a KMS driver <span style="color:#000088">for</span> emulated cirrus device <span style="color:#000088">in</span> qemu.
     It <span style="color:#000088">is</span> *<span style="color:#000088">NOT</span>* intended <span style="color:#000088">for</span> real cirrus devices. This requires
     the modesetting userspace X.org driver.</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

配置位置:

<span style="color:#000000"><code>    Device Drivers  <span style="color:#880000">---></span>
        Graphics support  <span style="color:#880000">---></span>
            Direct Rendering Manager  <span style="color:#880000">---></span>
                Direct Rendering Manager (XFree86 <span style="color:#006666">4.1</span><span style="color:#006666">.0</span> <span style="color:#000088">and</span> higher DRI support)  <span style="color:#880000">---></span>
                <*> Cirrus driver <span style="color:#000088">for</span> QEMU emulated device</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5

qemu启动命令行参数如下:

<span style="color:#000000"><code>qemu -m <span style="color:#006666">512</span> -kernel bzImage -append <span style="color:#009900">"root=/dev/sda rw"</span> -boot c -hda busybox<span style="color:#4f4f4f">.</span>img -k en-us -vga cirrus -net nic -net tap,ifname<span style="color:#4f4f4f">=</span>tap0,script<span style="color:#4f4f4f">=</span>no</code></span>
  • 1

  启动qemu之后,打开上面代码编译的应用程序可见bmp文件被完整的显示出来: 
这里写图片描述

  上面代码中调用函数 cursor_bitmap_format_convert 是由于bmp图象是从下至上存储的,所以我们不能进行直接顺序读取。详细的说,bmp图象存储区数据是从1078偏移字节开始。文件内第一个图象点实际上是对应图象(320*200)第200行的最左边的第一个点,而从1078开始的320个点则是图象最下面一行对应的点,之后的321个点是图象倒数第二行最左边的第一个点。这样,bmp文件最后一个字节对应的点是第一行最后边的点了。

关于bmp文件格式这里就不分析了,相对于jpeg等压缩格式,这个格式十分简单网上很多资料

注意:上面的程序只在framebuffer上显示图片,却没有删除刷新屏幕,可以使用下面的命令恢复屏幕

保存屏幕信息:dd if=/dev/fb0 of=fbfile 或: cp /dev/fb0 fbfile 
恢复屏幕信息:dd if=fbfile of=/dev/fb0 或: cat fbfile > /dev/fb0

bmp 位图文件:

drop上的文件,似乎这几天ss很难用,过几天再放上原图 
就是一个PC bitmap, Windows 3.x format, 1024 x 768 x 24 位图文件。

 

from: https://blog.csdn.net/xsckernel/article/details/49992315