linux显示子系统-framebuffer架构分析

目录

简介

驱动层

时序数据流

架构

应用层

实例

fb架构优劣势

参考文件

简介


FrameBuffer,帧缓冲,简称fb,也叫显存,下文以fb代表framebuffer。该子系统是内核针对显示系统提供出来的一个统一接口,应用层可以直接操作显存更改显示。

下面是一张示意图,左侧的图片通过framebuffer显示到panel上。写到framebuffer的数据是RGB数据或者ARGB数据。

 本文将从以下2个层面说明fb:

  1. 驱动层面
  2. 应用层面

驱动层


驱动层,主要从probe函数出发,重点分析2个问题:

  1. 设备树中配置的时序参数整个“生命”历程
  2. 整个架构

时序数据流

1、fb架构主要涉及4个结构体,层层包含的关系:

struct mxsfb_info:平台私有结构体

struct fb_info *fb_info

     struct fb_var_screeninfo var:设备树中的时序最后会存在 struct fb_var_screeninfo var 结构体中,应用层可以通过接口获取

     struct fb_fix_screeninfo fix:包含fb物理地址、长度等信息

2、结构体之间的关系

2.1、从设备中解析出来,放到 struct display_timings结构体中,经过一系列的转换最后放到struct fb_info结构体中

2.2、解析出来的消隐参数配置到寄存器中

小结:

分析完整个数据流可以发现:fb在内核中被抽象成一个fb_info结构体

架构

1、一个/dev/fb0、一个framebuffer、一套时序参数,这3者是怎么进行绑定的?

1.1、从open函数开始跟踪,发现如下逻辑:

1.2、答案是:通过次设备号绑定

驱动注册的时候是根据次设备号进行注册的,那打开的时候就可以根据次设备号找到对应的fb_info,进而可以获取到对应的帧缓冲区、对应的操作函数集。

2、已经知道整个框架的数据结构、以及之间的联系。下面看下整个架构图,图是网上的,链接是:framebuffer 入门介绍

2.1、基于上图,再补充一二,如下:

2.2、核心层和平台对应的函数集如下:

static const struct file_operations fb_fops = {
	.owner =	THIS_MODULE,
	.read =		fb_read,
	.write =	fb_write,
	.unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = fb_compat_ioctl,
#endif
	.mmap =		fb_mmap,
	.open =		fb_open,
	.release =	fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
	.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
	.fsync =	fb_deferred_io_fsync,
#endif
	.llseek =	default_llseek,
};
static struct fb_ops mxsfb_ops = {
	.owner = THIS_MODULE,
	.fb_check_var = mxsfb_check_var,
	.fb_set_par = mxsfb_set_par,
	.fb_setcolreg = mxsfb_setcolreg,
	.fb_ioctl = mxsfb_ioctl,
	.fb_blank = mxsfb_blank,
	.fb_pan_display = mxsfb_pan_display,
	.fb_mmap = mxsfb_mmap,
	.fb_fillrect = cfb_fillrect,
	.fb_copyarea = cfb_copyarea,
	.fb_imageblit = cfb_imageblit,
};

3、如前文所述,应用调用fb接口可以直接更改显存、更改画面显示。该功能主要在于fb_mmp函数,下面是fb_mmp函数的特点:

  • 显存的物理地址会被强制进行页对齐
  • 映射的长度也会被强制性调整为页的整数倍
  • 前2点受限于内核只能在页表一级上对虚拟地址进行管理

应用层


#include <unistd.h>  
#include <stdio.h>  
#include <fcntl.h>  
#include <linux/fb.h>  
#include <sys/mman.h>  
#include <errno.h>  
#include  <string.h>
#define BOOT_LOGO_SHOW   "/mnt/nfs0/logo"
#define BOOT_LOGO1_SHOW   "/mnt/nfs0/logo1"
#define BOOT_LOGO2_SHOW   "/mnt/nfs0/logo2"
#define BOOT_LOGO3_SHOW   "/mnt/nfs0/logo3"
unsigned char hilogo[4][1280*720*4];
int main()
{  
	int fp = 0;
	int lfd[4];
	int ret;
	int i =0;
	struct fb_var_screeninfo   vinfo;
	struct fb_fix_screeninfo   finfo;
	int screensize = 0;
	char *fbp = 0;
	int x = 0, y = 0;
	int location = 0;
	int bytes_per_pixel;
	fp = open("/dev/fb0", O_RDWR); //cyy commment: 打开要操作的fb
	if(fp < 0) {
		printf("open failed\n");
	}
	if(ioctl(fp, FBIOGET_FSCREENINFO, &finfo)) { //cyy commment: 获取一行长度等信息
		perror("ioctl");
	}
	if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)) { //cyy comment: 获取分辨率等信息
		perror("ioctl");  
	} 
	printf("x = %d  y = %d   vinfo.xoffset=%d, vinfo.yoffset=%d, finfo.line_length=%d\n",  vinfo.xres,  vinfo.yres, vinfo.xoffset, vinfo.yoffset, finfo.line_length); 
	bytes_per_pixel = vinfo.bits_per_pixel/8;
	screensize = vinfo.xres * vinfo.yres * bytes_per_pixel;
	printf("x = %d  y = %d   bytes_per_pixel = %d\n",  vinfo.xres,  vinfo.yres,  bytes_per_pixel);  
	printf("scrrensize = %d\n",  screensize);
	fbp = (char*) mmap(0,  screensize,  PROT_READ |PROT_WRITE,  MAP_SHARED, fp, 0x0); //cyy commment: 将显存的物理地址映射到应用空间
	if(fbp < 0) {
		perror("mmap");  
	}
	for(y = 0; y < vinfo.yres; y++) { //cyy commment: 对显存进行更改,显示不同图片
		for(x=0 ; x<vinfo.xres / 2; x++) {
			location = x * bytes_per_pixel + y * finfo.line_length;  
			*(fbp + location) = 0xff;
			*(fbp +location + 1) = 0xff;
			*(fbp + location + 2) = 0;
			*(fbp + location + 3) = 0xff;
		}  
		
		 for(; x<vinfo.xres; x++) {
			location = x * bytes_per_pixel + y * finfo.line_length;  
			*(fbp + location) = 0x00;
			*(fbp +location + 1) = 0x0;
			*(fbp + location + 2) = 0xff;
			*(fbp + location + 3) = 0xff;
		}
	}
	munmap(fbp, screensize); //cyy commment: 取消映射
	close(fp); //cyy commment: 关闭fb
}  

实例


实际测试时,左侧图片会显示到右侧,如下所示:

原因如下:

fb架构优劣势


  1. fb的优势是:使用户态可以直接写屏;LCD的HAL<Hard Abstraction Layer>
  2. fb的劣势:如果写的慢的话,图像显示会闪烁

参考文件


  1. framebuffer 入门介绍
  2. framebuffer显示原理以及缺点分析
  3. MMAP和普通文件读写对比
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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显示字符打印的详细信息,建议查阅相关的文档或参考示例代码。 希望这些信息对您有所帮助!如有任何进一步的问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值