framebuffer简介与应用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_28992301/article/details/52727342
         <!--一个博主专栏付费入口结束-->
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-d284373521.css">
                                    <div id="content_views" class="markdown_views">
                <!-- flowchart 箭头图标 勿删 -->
                <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                    <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                </svg>
                                        <h1 id="framebuffer简介与应用"><a name="t0"></a>framebuffer简介与应用</h1>

使用GUI测试framebuffer不太方便,最简单的方法是用应用层的小程序来测试

1.gpu与fb的关系

  • gpu就是soc中的一个外设,对外体现就是寄存器。cpu可以发命令给gpu,比如给两个端点,gpu就会去做具体的画线操作。这样就减轻了cpu的负担,有点类似于DMA的作用
  • 下图是一个典型的嵌入式系统显示机制

2.在系统中查看lcd参数

在测试前,最重要的就是把带有刷屏功能的应用程序关掉,否则我们无法观察到现象
输入 cat /sys/class/graphics/fb0/modes即可查看分辨率
输入cat /dev/urandom > /dev/fb0即可知晓fb是否能正常工作

3.控制fb

对于应用层,通过操作/dev/fb*,通过ioctl来用各种命令控制fb

  • 那么怎么控制呢?命令又是什么呢?这些都在<linux/fb.h>中提供。其实这个头文件是内核源码中的,由于交叉编译器中将其包含了,所以我们可以在应用层直接调用
  • 进入内核源码中看看<linux/fb.h>,里面定义了一些ioctl的命令
/* ioctls
   0x46 is 'F'                              */
#define FBIOGET_VSCREENINFO 0x4600
#define FBIOPUT_VSCREENINFO 0x4601
#define FBIOGET_FSCREENINFO 0x4602
#define FBIOGETCMAP     0x4604
#define FBIOPUTCMAP     0x4605
#define FBIOPAN_DISPLAY     0x4606

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我们主要使用FBIOGET_VSCREENINFOFBIOGET_FSCREENINFO 命令。从字面意思我们不难看出,这两个命令的意思分别为

  • fb’s ioctl, to get variable screen info:获取应用程序可改变的参数(如设定的分辨率)
  • fb’s ioctl, to get fixed screen info:获取固定的参数(如屏幕的分辨率,一般只是拿来看看)
  • <linux/fb.h>中还提供了专门的结构体类型,用来存放上述两个参数,如下就是存放可变参数的结构体类型
struct fb_var_screeninfo {
    __u32 xres;         /* visible resolution       */
    __u32 yres;
    __u32 xres_virtual;     /* virtual resolution       */
    __u32 yres_virtual;
    __u32 xoffset;          /* offset from virtual to visible */
    __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 */


 
 
  • 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
  • 比较重要的可变参数有:
    • xres、yres:可视画面的x、y轴分辨率(应用层改不了)
    • xres_virtual、yres_virtual:虚拟画面(即fb)x、y轴分辨率
    • xoffset、yoffset:可视画面相对于虚拟画面的x、y轴偏移量
    • bits_per_pixel:像素深度,详见LCD详解
      这里写图片描述
  • 虚拟画面一般会被默认设为(不一定的)可视画面的两倍,这种结构被称之为“双缓冲机制”,这样做的好处是可以一边显示,一边缓冲下一幅画面
    这里写图片描述

4.建立显存映射

  • 显示画面的输出,实际是通过往显存里面写像素数据来实现的。由于显存实际是处于内核态的物理内存,所以下一步要把这块物理内存映射到用户态,所谓“映射”就可以理解为建立了一个“符号链接”,这样应用程序就可以直接操作这块物理内存了
  • 建立映射主要是使用mmap这个api,mmap的原型可以用man手册查看,
    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
    值得注意的是第一个参数,第一个参数是自选地址,意思是应用程序可以选一个自己喜欢的地址值,然后mmap可以把显存映射到该地址。如果参数值为NULL的话,系统将为我们自动分配一个地址,返回值就是该地址。
    其他参数没什么好注意的,看看man手册即可

5.输出画面数据

  • 我们有了显存之后,就可以将画面数据写入显存了。可是怎么写,写什么呢?
  • 对于我们当前的环境, xres_virtual、yres_virtual分别为800,960;bpp(像素深度)为32位;所以每个像素用一个int来表示,虚拟屏幕尺寸为800*960像素。
  • 显存中,数据排布的顺序就是按照虚拟屏幕中像素数据从上到下,从左到右的数据来排布。而每一个像素数据则按照A(透明度)、R(红)、G(绿)、B(蓝)的顺序排布的。说实话显存中数据的排布很简单,非常符合人类的思维
    这里写图片描述
    这里写图片描述

6.程序分析

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>


#define FBDEVICE "/dev/fb0"
void draw_back(unsigned int *pfb, unsigned int width, unsigned int height, unsigned int color);

void draw_line(unsigned int *pfb, unsigned int width, unsigned int height);

int main(void)
{
    int fd = -1;
    int ret = -1;
    unsigned int *pfb = NULL;
    struct fb_fix_screeninfo finfo;
    struct fb_var_screeninfo vinfo;

    fd = open(FBDEVICE, O_RDWR);
    if (fd < 0)
    {
        perror("open");
        return -1;
    }
    printf("open %s success \n", FBDEVICE);

    /*获取fb信息*/
    ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
    if (ret < 0)
    {
        perror("ioctl");
        return -1;
    }

    ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
    if (ret < 0)
    {
        perror("ioctl");
        return -1;
    }
    /*建立mmap映射*/
    pfb = mmap(NULL, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (NULL == pfb)
    {
        perror("mmap");
        return -1;
    }
    printf("pfb :0x%x \n", pfb);

    draw_back(pfb, vinfo.xres_virtual, vinfo.yres_virtual, 0xffff0000);
    draw_line(pfb, vinfo.xres_virtual, vinfo.yres_virtual);

    close(fd);
    return 0;
}


void draw_back(unsigned int *pfb, unsigned int width, unsigned int height, unsigned int color)
{
    unsigned int x, y;
    for (y = 0; y < height; y++)
    {
        for (x = 0; x < width; x++)
        {
            *(pfb + y * width + x) = color;
        }
    }
}

void draw_line(unsigned int *pfb, unsigned int width, unsigned int height)
{
    unsigned int x, y;
    for (x = 50; x < width - 50; x++)
    {
        *(pfb + 50 * width + x) = 0xffffff00;
    }
    for (y = 50; y < height -50; y++)
    {
        *(pfb + y * width + 50) = 0xffffff00;
    }
}
 
 
  • 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
  • 上述代码先读取了fb的各种信息,然后根据读出来的信息画了一幅图像(两条线距离显示virtual边缘为50像素),如果该图像能被正确显示,则说明fb完全正常
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Framebuffer应用是指在Linux系统中使用Framebuffer驱动程序来控制LCD显示设备。Framebuffer是一块内存,保存着一帧图像的每一个像素颜色值。通过设置LCD控制器的时序、信号极性以及分配Framebuffer的大小和位置,可以实现在LCD上显示图像。在应用层,可以使用ioctl函数读取屏幕的参数信息,然后通过mmap映射Framebuffer,在Framebuffer中写入数据来实现图像的显示。Framebuffer应用的好处是可以直接对显存缓冲区进行读写操作,不必关心硬件的物理地址,简化了读写速度和方便性。\[2\]\[3\] #### 引用[.reference_title] - *1* [Framebuffer的配置及应用——先转载留着,以后一定要弄懂](https://blog.csdn.net/weixin_33890499/article/details/85844617)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [【嵌入式Linux】嵌入式Linux应用开发基础知识之Framebuffer应用编程和字符汉字显示](https://blog.csdn.net/weixin_43444989/article/details/122918794)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [19.Frambuffer应用编程](https://blog.csdn.net/qq_42174306/article/details/125589673)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值