免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 103496 | 回复: 7
打印 上一主题 下一主题

[驱动] Framebuffer原理、使用、测试系列文章 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-04-24 15:31 |显示全部楼层 |倒序浏览
本帖最后由 sep 于 2010-04-24 15:45 编辑

上一篇文章居然加精了。现在继续将自己收集的一些资料和工作中的心得总结贴出来,我很多工作可能和大家没多大的通用性,所以只能挑有限的一些文章。如果有同学是做音视频编解码或图像处理的,可以交流下,我现在业余做这个。

上年做过fb的驱动,收集了不少这方面的文章,不过建议大家还是要多看内核驱动代码,read the fucking code是真理。代码为主,其他为辅。

首先第一篇是《Framebuffer原理、实现与应用》,该文写得很有条理而且简洁,不可多得。可惜我愣是找不到原出处,不知道原作者是谁。【2、3楼】
第二篇是《Framebuffer的配置及应用》,用于测试fb的备忘录。【4楼】
第三篇是我整理的《Framebuffer使用测试》,写了一个测试代码,用于显示red、blue、green矩阵和计算fb的性能如fps。【5、6楼】

论坛徽章:
0
2 [报告]
发表于 2010-04-24 15:34 |显示全部楼层
Framebuffer的配置及应用

*一、FrameBuffer的原理*
FrameBuffer 是出现在 2.2.xx 内核当中的一种驱动程序接口。
Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这 个设备来供用户态进程实现直接写屏。Framebuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过Framebuffer的读写直接对显存进行操 作。用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操 作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer设备驱动来完成的。
    但Framebuffer本身不具备任何运算数据的能力,就只好比是一个暂时存放水的水池.CPU将运算后的结果放到这个水池,水池再将结果流到显示器.中间不会对数据做处理. 应用程序也可以直接读写这个水池的内容.在这种机制下,尽管Framebuffer需要真正的显卡驱动的支持,但所有显示任务都有CPU完成,因此CPU负担很重.
framebuffer的设备文件一般是 /dev/fb0、/dev/fb1 等等。
可以用命令: #dd if=/dev/zero of=/dev/fb 清空屏幕.
如果显示模式是 1024x768-8 位色,用命令:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768 清空屏幕;
用命令: #dd if=/dev/fb of=fbfile  可以将fb中的内容保存下来;
可以重新写回屏幕: #dd if=fbfile of=/dev/fb;
在使用Framebuffer时,Linux是将显卡置于图形模式下的.

    在应用程序中,一般通过将 FrameBuffer 设备映射到进程地址空间的方式使用,比如下面的程序就打开 /dev/fb0 设备,并通过mmap 系统调用进行地址映射,随后用 memset 将屏幕清空(这里假设显示模式是 1024x768-8 位色模式,线性内存模式):
int fb;
unsigned char* fb_mem;
fb = open ("/dev/fb0", O_RDWR);
fb_mem = mmap (NULL, 1024*768, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
memset (fb_mem, 0, 1024*76;

    FrameBuffer 设备还提供了若干ioctl命令,通过这些命令,可以获得显示设备的一些固定信息(比如显示内存大小)、与显示模式相关的可变信息(比如分辨率、象素结构、每扫描线的字节宽度),以及伪彩 色模式下的调色板信息等等。
    通过 FrameBuffer设备,还可以获得当前内核所支持的加速显示卡的类型(通过固定信息得到),这种类型通常是和特定显示芯片相关的。比如目前最新的内核(2.4.9)中,就包含有 对S3、Matrox、nVidia、3Dfx 等等流行显示芯片的加速支持。在获得了加速芯片类型之后,应用程序就可以将 PCI设备的内存I/O(memio)映射到进程的地址空间。这些memio
一般是用来控制显示卡的寄存器,通过对这些寄存器的操作,应用程序就可以控制特定显卡的加速功能。
    PCI设备可以将自己的控制寄存器映射到物理内存空间,而后,对这些控制寄存器的访问,给变成了对物理内存的访问。因此,这些寄存器又被称为"memio"。一旦被映 射到物理内存,Linux的普通进程就可以通过 mmap 将这些内存 I/O 映射到进程地址空间,这样就可以直接访问这些寄存器了。
    当然,因为不同的显示芯片具有不同的加速能力,对memio的使用和定义也各自不同,这时,就需要针对加速芯片的不同类型来编写实现不同的加速功能。比如大多数芯片都提供了对矩形填充的硬件加速支持,但不同的芯片实现方 式不同,这时,就需要针对不同的芯片类型编写不同的用来完成填充矩形的函数。
    FrameBuffer 只是一个提供显示内存和显示芯片寄存器从物理内存映射到进程地址空间中的设备。所以,对于应用程序而言,如果希望在FrameBuffer 之上进行图形编程,还需要自己动手完成其他许多工作。

*二、FrameBuffer在Linux中的实现和机制*
Framebuffer对应的源文件在linux/drivers/video/目录下。总的抽象设备文件为fbcon.c,在这个目录下还有与各种显卡驱动相关的源文件。
(一)、分析Framebuffer设备驱动
    需要特别提出的是在INTEL平台上,老式的VESA1.2卡,如CGA/EGA卡,是不能支持Framebuffer的,因为Framebuffer要求显卡支持线性帧缓冲,即CPU可以访问显缓冲中的每一位, 但是VESA1.2 卡只能允许CPU一次访问64K的地址空间。
FrameBuffer设备驱动基于如下两个文件:
1) linux/include/linux/fb.h
2) linux/drivers/video/fbmem.c 下面分析这两个文件。
1、fb.h
   几乎主要的结构都是在这个中文件定义的。这些结构包括:
1)fb_var_screeninfo
   这个结构描述了显示卡的特性:
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 resolution */
__u32 yoffset;
__u32 bits_per_pixel; /* guess what */
__u32 grayscale; /* != 0 Gray levels 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; /* acceleration flags (hints) */
/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */
__u32 vsync_len; /* length of vertical sync */
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 reserved[6]; /* Reserved for future compatibility */
};


2) fb_fix_screeninfon
这个结构在显卡被设定模式后创建,它描述显示卡的属性,并且系统运行时不能被修改;比如FrameBuffer内存的起始地址。它依赖于被设定的模式,当一个模 式被设定后,内存信息由显示卡硬件给出,内存的位置等信息就不可以修改。
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
__u32 smem_len; /* Length of frame buffer mem */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O */
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Type of acceleration available */
__u16 reserved[3]; /* Reserved for future compatibility */
};


3) fb_cmap
描述设备无关的颜色映射信息。可以通过FBIOGETCMAP 和 FBIOPUTCMAP 对应的ioctl操作设定或获取颜色映射信息.
struct fb_cmap {
__u32 start; /* First entry */
__u32 len; /* Number of entries */
__u16 *red; /* Red values */
__u16 *green;
__u16 *blue;
__u16 *transp; /* transparency, can be NULL */
};


4) fb_info
定义当显卡的当前状态;fb_info结构仅在内核中可见,在这个结构中有一个fb_ops指针, 指向驱动设备工作所需的函数集。
struct fb_info {
char modename[40]; /* default video mode */
kdev_t node;
int flags;
int open; /* Has this been open already ? */
#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct fb_cmap cmap; /* Current cmap */
struct fb_ops *fbops;
char *screen_base; /* Virtual address */
struct display *disp; /* initial display variable */
struct vc_data *display_fg; /* Console visible on this display */
char fontname[40]; /* default font name */
devfs_handle_t devfs_handle; /* Devfs handle for new name */
devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */
int (*changevar)(int); /* tell console var has changed */
int (*switch_con)(int, struct fb_info*);
/* tell fb to switch consoles */
int (*updatevar)(int, struct fb_info*);
/* tell fb to update the vars */
void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */
/* arg = 0: unblank */
/* arg > 0: VESA level (arg-1) */
void *pseudo_palette; /* Fake palette of 16 colors and
the cursor's color for non
palette mode */
/* From here on everything is device dependent */
void *par;
};


5) struct fb_ops
用户应用可以使用ioctl()系统调用来操作设备,这个结构就是用一支持ioctl()的这些操作的。
struct fb_ops {
/* open/release and usage marking */
struct module *owner;
int (*fb_open)(struct fb_info *info, int user);
int (*fb_release)(struct fb_info *info, int user);
/* get non settable parameters */
int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
/* get settable parameters */
int (*fb_get_var)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* set settable parameters */
int (*fb_set_var)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* get colormap */
int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
/* set colormap */
int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
/* pan display (optional) */
int (*fb_pan_display)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* perform fb specific ioctl (optional) */
int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg, int con, struct fb_info *info);
/* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct file *file, struct
vm_area_struct *vma);
/* switch to/from raster image mode */
int (*fb_rasterimg)(struct fb_info *info, int start);
};


6) structure map
struct fb_info_gen | struct fb_info | fb_var_screeninfo
| | fb_fix_screeninfo
| | fb_cmap
| | modename[40]
| | fb_ops ---|--->ops on var
| | ... | fb_open
| | | fb_release
| | | fb_ioctl
| | | fb_mmap
| struct fbgen_hwswitch -|-> detect
| | encode_fix
| | encode_var
| | decode_fix
| | decode_var
| | get_var
| | set_var
| | getcolreg
| | setcolreg
| | pan_display
| | blank
| | set_disp
[编排有点困难,第一行的第一条竖线和下面的第一列竖线对齐,第一行的第二条竖线和下面的第二列竖线对齐就可以了]
这个结构 fbgen_hwswitch抽象了硬件的操作.虽然它不是必需的,但有时候很有用.
2、 fbmem.c
fbmem.c 处于Framebuffer设备驱动技术的中心位置.它为上层应用程序提供系统调用也为下一层的特定硬件驱动提供接口;那些底层硬件驱动需要用到这儿的接口来向 系统内核注册它们自己.
fbmem.c 为所有支持FrameBuffer的设备驱动提供了通用的接口,避免重复工作.
1) 全局变量
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
这两变量记录了所有fb_info 结构的实例,fb_info 结构描述显卡的当前状态,所有设备对应的fb_info结构都保存在这个数组中,当一个FrameBuffer设备驱动向系统注册自己时,其对应的fb_info结构就会添加到这个结构中,同时num_registered_fb 为自动加1. static struct {
const char *name;
int (*init)(void);
int (*setup)(void);
} fb_drivers[] __initdata= { ....};


如果FrameBuffer设备被静态链接到内核,其对应的入口就会添加到这个表中;如果是动态加载的,即使用insmod/rmmod,就不需要关心这个表。
static struct file_operations fb_ops ={
owner: THIS_MODULE,
read: fb_read,
write: fb_write,
ioctl: fb_ioctl,
mmap: fb_mmap,
open: fb_open,
release: fb_release
};


这是一个提供给应用程序的接口.
2)fbmem.c 实现了如下函数.
register_framebuffer(struct fb_info *fb_info);
unregister_framebuffer(struct fb_info *fb_info);
这两个是提供给下层FrameBuffer设备驱动的接口,设备驱动通过这两函数向系统注册或注销自己。几乎底层设备驱动所要做的所有事情就是填充fb_inf o结构然后向系统注册或注销它。
(二)一个LCD显示芯片的驱动实例
    以Skeleton LCD控制器驱动为例,在LINUX中存有一个/fb/skeleton.c的skeleton的Framebuffer驱动程序,很简单,仅仅是填充了fb_info结构,并且注册/注销自己。设备驱动是向用户程序提供系统调用接口,所以我们需要实现底层硬件操作并且定义file_operations结构来向系统提供系统调用接口,从而实现更有效的LCD控制器驱动程序。
1)在系统内存中分配显存
在fbmem.c文件中可以看到,file_operations结构中的open()和release()操作不需底层支持,但read()、write()和 mmap()操作需要函数fb_get_fix()的支持.因此需要重新实现函数fb_get_fix()。另外还需要在系统内存中分配显存空间,大多数的LCD控制器都没有自己的显存空间,被分配的地址空间的起 始地址与长度将会被填充到fb_fix_screeninfo结构的smem_start 和smem_len 的两个变量中.被分配的空间必须是物理连续的。
2)实现 fb_ops 中的函数
用户应用程序通过ioctl()系统调用操作硬件,fb_ops 中的函数就用于支持这些操作。(注: fb_ops结构与file_operations结构不同,fb_ops是底层操作的抽象,而file_operations是提供给上层系统调用的接口,可以直接调用ioctl()系统调用在文件fbmem.c中实现,通过观察可以发现ioctl()命令与fb_ops's 中函数的关系:
FBIOGET_VSCREENINFO fb_get_var
FBIOPUT_VSCREENINFO fb_set_var
FBIOGET_FSCREENINFO fb_get_fix
FBIOPUTCMAP fb_set_cmap
FBIOGETCMAP fb_get_cmap
FBIOPAN_DISPLAY fb_pan_display 如果我们定义了fb_XXX_XXX 方法,用户程序就可以使用FBIOXXXX宏的ioctl()操作来操作硬件。
文件linux/drivers/video/fbgen.c或者linux/drivers/video目录下的其它设备驱动是比较好的参考资料。在所有的这 些函数中fb_set_var()是最重要的,它用于设定显示卡的模式和其它属性,下面是函数fb_set_var()的执行步骤:
1)检测是否必须设定模式
2)设定模式
3)设定颜色映射
4) 根据以前的设定重新设置LCD控制器的各寄存器。
第四步表明了底层操作到底放置在何处。在系统内存中分配显存后,显存的起始地址及长度将被设定到LCD控制器的各寄存器中(一般通过fb_set_var()函数),显存中的内容将自动被LCD控制器输出到屏幕上。另一方面,用户程序通过函数mmap()将显存映射到用户进程地址空间中,然后用户进程向映射空间发送 的所有数据都将会被显示到LCD显示器上。

论坛徽章:
0
3 [报告]
发表于 2010-04-24 15:37 |显示全部楼层
Framebuffer的配置及应用


借助于framebuffer,我们能够在console下面作很多事情。首先下载framebuffer的配置工具fbset:
# apt-get install fbset 下载完毕后,配置文件/etc/fb.modes随之产生。

比较简单的作法是用万能的vesafb,如果它被编译进了内核,如:
Device Drivers -> Graphics support ->
  • VESA VGA graphics support
    那么在grub内核引导那一行的后面加上vga=791 它的含义是VESA framebuffer console @ 1024x768x64k,进入系统后可以直接使用framebuffer,看一下这种情况下的各项数据:
    # fbset -s
    mode "1024x768-76"
        # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz
        geometry 1024 768 1024 768 16
        timings 12714 128 32 16 4 128 4
        rgba 5/11,6/5,5/0,0/0
    endmode

    用具体显卡的framebuffer驱动是另一种选择,拿Nvidia显卡为例,Nvidia显卡的xorg驱动模块与其framebuffer的驱动模块是互相排斥的,如果要用一个就必须清除另一个:
    # rmmod nvidia
    装载nvidia的framebuffer驱动:
    # modprobe nvidiafb
    装载成功的时候,会产生/dev/fb0设备,console屏幕上的字体会有变化。
    看一下当前的配置:
    # fbset -s
    mode "1024x768-85"
        # D: 94.500 MHz, H: 68.677 kHz, V: 84.997 Hz
        geometry 1024 768 1024 32767 8
        timings 10582 208 48 36 1 96 3
        hsync high
        vsync high
        accel true
        rgba 8/0,8/0,8/0,0/0
    endmode

    需要改变一下geometry及色深:
    # fbset -g 1024 768 1024 768 32
    # fbset -s
    mode "1024x768-85"
        # D: 94.500 MHz, H: 68.677 kHz, V: 84.997 Hz
        geometry 1024 768 1024 768 32
        timings 10582 208 48 36 1 96 3
        hsync high
        vsync high
        accel true
        rgba 8/16,8/8,8/0,8/24
    endmode

    我们把它与使用VESA ramebuffer后的数据比较一下,显然,根据具体的显卡来驱动framebuffer可以在颜色上达到最佳值,好,现在我们在console下面能够作的事情:
    一、视频播放,可以用mplayer 或者 fbxine:
    # mplayer -vo fbdev -vf scale=1024:768 video_file.avi
    -vo fbdev 是告诉mplayer用framebuffer作视频驱动.
    -vf scale=1024:768 是全屏的方法,可按屏幕的具体情况作调整
    用fbxine的话需要下载:
    # apt-get install xine-console
    二、图片文件与pdf文件浏览:
    # apt-get install fbi
    用这个软件包里的fbi可以浏览图片,fbgs可以观看pdf文件:
    # fbi -a *jpg
    # fbgs -c *pdf
    三、中文显示:
    # apt-get install jfbterm
    # jfbterm
    中文显示的效果完美。

    文章出处:飞诺网(http://www.diybl.com/course/6_system/linux/Linuxjs/2008721/133651.html)

    ------------------------------------------------------------------------
    在内核Documentation/fb/vesafb.txt文件中,有如下vesa-framebuffer的说明
    Switching modes is done using the vga=... boot parameter. Read
    Documentation/svga.txt for details.
    You should compile in both vgacon (for text mode) and vesafb (for
    graphics mode). Which of them takes over the console depends on
    whenever the specified mode is text or graphics.
    The graphic modes are NOT in the list which you get if you boot with
    vga=ask and hit return. The mode you wish to use is derived from the
    VESA mode number. Here are those VESA mode numbers:
    | 640x480 800x600 1024x768 1280x1024
    ----+-------------------------------------
    256 | 0x101 0x103 0x105 0x107 8位色
    32k | 0x110 0x113 0x116 0x119 15位色
    64k | 0x111 0x114 0x117 0x11A 16位色
    16M | 0x112 0x115 0x118 0x11B 24位色
    The video mode number of the Linux kernel is the VESA mode number plus
    0x200.
    Linux_kernel_mode_number = VESA_mode_number + 0x200
    So the table for the Kernel mode numbers are:
    | 640x480 800x600 1024x768 1280x1024
    ----+-------------------------------------
    256 | 0x301 0x303 0x305 0x307 8位色
    32k | 0x310 0x313 0x316 0x319 15位色
    64k | 0x311 0x314 0x317 0x31A 16位色
    16M | 0x312 0x315 0x318 0x31B 24位色
    To enable one of those modes you have to specify "vga=ask" in the
    lilo.conf file and rerun LILO. Then you can type in the desired
    mode at the "vga=ask" prompt. For example if you like to use
    1024x768x256 colors you have to say "305" at this prompt.
    If this does not work, this might be because your BIOS does not support
    linear framebuffers or because it does not support this mode at all.
    Even if your board does, it might be the BIOS which does not. VESA BIOS
    Extensions v2.0 are required, 1.2 is NOT sufficient. You will get a
    "bad mode number" message if something goes wrong.
    1. Note: LILO cannot handle hex, for booting directly with
    "vga=mode-number" you have to transform the numbers to decimal.
    2. Note: Some newer versions of LILO appear to work with those hex values,
    if you set the 0x in front of the numbers.
    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/songbohr/archive/2010/03/25/5415637.aspx
  • 论坛徽章:
    0
    4 [报告]
    发表于 2010-04-24 15:39 |显示全部楼层
    Framebuffer使用测试

    这两天拾起以前做过的Framebuffer,不相同的是以前在嵌入式上做的,现在在自己电脑上Debian上进行测试,不过都类似罢了,嵌入式里要初始化很多东西。下面具体列一下步骤。至于Framebuffer的原理,就我的理解是比较简单的,无非往mmap好的fb上填写显示数据罢了,不对这些数据进行处理,FrameBuffer 只是一个提供显示内存和显示芯片寄存器从物理内存映射到进程地址空间中的设备,它需要真正的显卡驱动的支持。在这次测试中,我用了默认就安装的vesafb,好像又被称为万能Fb驱动。

    1、   首先在系统Grub启动时按e进入命令启动行的编辑模式,改为:kernel /boot/vmlinuz-2.6.18-5-686 root=/dev/sda6 ro vga=791vga=791表示fb1024 * 768 * 16bpp,其他模式的参数可以上网查查);

    2、   进入系统的命令行模式,编译fb测试例子:gcc fb_test.c

    3、   允许测试例子:sudo ./a.out >> fb.txt(必须要用超级用户权限,>>将屏幕打印写到fb.txt中),效果如下:

    打印如下:


    Fixed screen info:
        id: VESA VGA
        smem_start: 0xf0000000
        smem_len: 3145728
        type: 0
        type_aux: 0
        visual: 2
        xpanstep: 0
        ypanstep: 0
        ywrapstep: 0
        line_length: 2048
        mmio_start: 0x0
        mmio_len: 0
        accel: 0

    Variable screen info:
        xres: 1024
        yres: 768
        xres_virtual: 1024
        yres_virtual: 768
        yoffset: 0
        xoffset: 0
        bits_per_pixel: 16
        grayscale: 0
        red: offset: 11, length: 5, msb_right: 0
        green: offset: 5, length: 6, msb_right: 0
        blue: offset: 0, length: 5, msb_right: 0
        transp: offset: 0, length: 0, msb_right: 0
        nonstd: 0
        activate: 0
        height: -1
        width: -1
        accel_flags: 0x0
        pixclock: 12714
        left_margin: 128
        right_margin: 32
        upper_margin: 16
        lower_margin: 4
        hsync_len: 128
        vsync_len: 4
        sync: 0
        vmode: 0

    Frame Buffer Performance test...
            Average: 2508 usecs
            Bandwidth: 1196.172 MByte/Sec
            Max. FPS: 398.724 fps


    4、还可以通过fb在命令行模式下看视频,如:sudo mplayer –vo fbdev ./air_nessesity.mpg





    论坛徽章:
    0
    5 [报告]
    发表于 2010-04-24 15:40 |显示全部楼层

    1. #include <stdlib.h>
    2. #include <unistd.h>
    3. #include <stdio.h>
    4. #include <fcntl.h>
    5. #include <linux/fb.h>
    6. #include <linux/kd.h>
    7. #include <sys/mman.h>
    8. #include <sys/ioctl.h>
    9. #include <sys/time.h>
    10. #include <string.h>
    11. #include <errno.h>

    12. struct fb_var_screeninfo vinfo;
    13. struct fb_fix_screeninfo finfo;
    14. char *frameBuffer = 0;

    15. //打印fb驱动中fix结构信息,注:在fb驱动加载后,fix结构不可被修改。
    16. void
    17. printFixedInfo ()
    18. {
    19.     printf ("Fixed screen info:\n"
    20.             "\tid: %s\n"
    21.             "\tsmem_start: 0x%lx\n"
    22.             "\tsmem_len: %d\n"
    23.             "\ttype: %d\n"
    24.             "\ttype_aux: %d\n"
    25.             "\tvisual: %d\n"
    26.             "\txpanstep: %d\n"
    27.             "\typanstep: %d\n"
    28.             "\tywrapstep: %d\n"
    29.             "\tline_length: %d\n"
    30.             "\tmmio_start: 0x%lx\n"
    31.             "\tmmio_len: %d\n"
    32.             "\taccel: %d\n"
    33.             "\n",
    34.             finfo.id, finfo.smem_start, finfo.smem_len, finfo.type,
    35.             finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep,
    36.             finfo.ywrapstep, finfo.line_length, finfo.mmio_start,
    37.             finfo.mmio_len, finfo.accel);
    38. }

    39. //打印fb驱动中var结构信息,注:fb驱动加载后,var结构可根据实际需要被重置
    40. void
    41. printVariableInfo ()
    42. {
    43.     printf ("Variable screen info:\n"
    44.             "\txres: %d\n"
    45.             "\tyres: %d\n"
    46.             "\txres_virtual: %d\n"
    47.             "\tyres_virtual: %d\n"
    48.             "\tyoffset: %d\n"
    49.             "\txoffset: %d\n"
    50.             "\tbits_per_pixel: %d\n"
    51.             "\tgrayscale: %d\n"
    52.             "\tred: offset: %2d, length: %2d, msb_right: %2d\n"
    53.             "\tgreen: offset: %2d, length: %2d, msb_right: %2d\n"
    54.             "\tblue: offset: %2d, length: %2d, msb_right: %2d\n"
    55.             "\ttransp: offset: %2d, length: %2d, msb_right: %2d\n"
    56.             "\tnonstd: %d\n"
    57.             "\tactivate: %d\n"
    58.             "\theight: %d\n"
    59.             "\twidth: %d\n"
    60.             "\taccel_flags: 0x%x\n"
    61.             "\tpixclock: %d\n"
    62.             "\tleft_margin: %d\n"
    63.             "\tright_margin: %d\n"
    64.             "\tupper_margin: %d\n"
    65.             "\tlower_margin: %d\n"
    66.             "\thsync_len: %d\n"
    67.             "\tvsync_len: %d\n"
    68.             "\tsync: %d\n"
    69.             "\tvmode: %d\n"
    70.             "\n",
    71.             vinfo.xres, vinfo.yres, vinfo.xres_virtual, vinfo.yres_virtual,
    72.             vinfo.xoffset, vinfo.yoffset, vinfo.bits_per_pixel,
    73.             vinfo.grayscale, vinfo.red.offset, vinfo.red.length,
    74.             vinfo.red.msb_right, vinfo.green.offset, vinfo.green.length,
    75.             vinfo.green.msb_right, vinfo.blue.offset, vinfo.blue.length,
    76.             vinfo.blue.msb_right, vinfo.transp.offset, vinfo.transp.length,
    77.             vinfo.transp.msb_right, vinfo.nonstd, vinfo.activate,
    78.             vinfo.height, vinfo.width, vinfo.accel_flags, vinfo.pixclock,
    79.             vinfo.left_margin, vinfo.right_margin, vinfo.upper_margin,
    80.             vinfo.lower_margin, vinfo.hsync_len, vinfo.vsync_len,
    81.             vinfo.sync, vinfo.vmode);
    82. }

    83. //画大小为width*height的同色矩阵,8alpha+8reds+8greens+8blues
    84. void
    85. drawRect_rgb32 (int x0, int y0, int width, int height, int color)
    86. {
    87.     const int bytesPerPixel = 4;
    88.     const int stride = finfo.line_length / bytesPerPixel;

    89.     int *dest = (int *) (frameBuffer)
    90.         + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset);

    91.     int x, y;
    92.     for (y = 0; y < height; ++y)
    93.     {
    94.         for (x = 0; x < width; ++x)
    95.         {
    96.             dest[x] = color;
    97.         }
    98.         dest += stride;
    99.     }
    100. }

    101. //画大小为width*height的同色矩阵,5reds+6greens+5blues
    102. void
    103. drawRect_rgb16 (int x0, int y0, int width, int height, int color)
    104. {
    105.     const int bytesPerPixel = 2;
    106.     const int stride = finfo.line_length / bytesPerPixel;
    107.     const int red = (color & 0xff0000) >> (16 + 3);
    108.     const int green = (color & 0xff00) >> (8 + 2);
    109.     const int blue = (color & 0xff) >> 3;
    110.     const short color16 = blue | (green << 5) | (red << (5 + 6));

    111.     short *dest = (short *) (frameBuffer)
    112.         + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset);

    113.     int x, y;
    114.     for (y = 0; y < height; ++y)
    115.     {
    116.         for (x = 0; x < width; ++x)
    117.         {
    118.             dest[x] = color16;
    119.         }
    120.         dest += stride;
    121.     }
    122. }

    123. //画大小为width*height的同色矩阵,5reds+5greens+5blues
    124. void
    125. drawRect_rgb15 (int x0, int y0, int width, int height, int color)
    126. {
    127.     const int bytesPerPixel = 2;
    128.     const int stride = finfo.line_length / bytesPerPixel;
    129.     const int red = (color & 0xff0000) >> (16 + 3);
    130.     const int green = (color & 0xff00) >> (8 + 3);
    131.     const int blue = (color & 0xff) >> 3;
    132.     const short color15 = blue | (green << 5) | (red << (5 + 5)) | 0x8000;

    133.     short *dest = (short *) (frameBuffer)
    134.         + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset);

    135.     int x, y;
    136.     for (y = 0; y < height; ++y)
    137.     {
    138.         for (x = 0; x < width; ++x)
    139.         {
    140.             dest[x] = color15;
    141.         }
    142.         dest += stride;
    143.     }
    144. }

    145. void
    146. drawRect (int x0, int y0, int width, int height, int color)
    147. {
    148.     switch (vinfo.bits_per_pixel)
    149.     {
    150.     case 32:
    151.         drawRect_rgb32 (x0, y0, width, height, color);
    152.         break;
    153.     case 16:
    154.         drawRect_rgb16 (x0, y0, width, height, color);
    155.         break;
    156.     case 15:
    157.         drawRect_rgb15 (x0, y0, width, height, color);
    158.         break;
    159.     default:
    160.         printf ("Warning: drawRect() not implemented for color depth %i\n",
    161.                 vinfo.bits_per_pixel);
    162.         break;
    163.     }
    164. }

    165. #define PERFORMANCE_RUN_COUNT 5
    166. void
    167. performSpeedTest (void *fb, int fbSize)
    168. {
    169.     int i, j, run;
    170.     struct timeval startTime, endTime;
    171.     unsigned long long results[PERFORMANCE_RUN_COUNT];
    172.     unsigned long long average;
    173.     unsigned int *testImage;

    174.     unsigned int randData[17] = {
    175.         0x3A428472, 0x724B84D3, 0x26B898AB, 0x7D980E3C, 0x5345A084,
    176.         0x6779B66B, 0x791EE4B4, 0x6E8EE3CC, 0x63AF504A, 0x18A21B33,
    177.         0x0E26EB73, 0x022F708E, 0x1740F3B0, 0x7E2C699D, 0x0E8A570B,
    178.         0x5F2C22FB, 0x6A742130
    179.     };

    180.     printf ("Frame Buffer Performance test...\n");
    181.     for (run = 0; run < PERFORMANCE_RUN_COUNT; ++run)
    182.     {
    183.         /* Generate test image with random(ish) data: */
    184.         testImage = (unsigned int *) malloc (fbSize);
    185.         j = run;
    186.         for (i = 0; i < (int) (fbSize / sizeof (int)); ++i)
    187.         {
    188.             testImage[i] = randData[j];
    189.             j++;
    190.             if (j >= 17)
    191.                 j = 0;
    192.         }

    193.         gettimeofday (&startTime, NULL);
    194.         memcpy (fb, testImage, fbSize);
    195.         gettimeofday (&endTime, NULL);

    196.         long secsDiff = endTime.tv_sec - startTime.tv_sec;
    197.         results[run] =
    198.             secsDiff * 1000000 + (endTime.tv_usec - startTime.tv_usec);

    199.         free (testImage);
    200.     }

    201.     average = 0;
    202.     for (i = 0; i < PERFORMANCE_RUN_COUNT; ++i)
    203.         average += results[i];
    204.     average = average / PERFORMANCE_RUN_COUNT;

    205.     printf (" Average: %llu usecs\n", average);
    206.     printf (" Bandwidth: %.03f MByte/Sec\n",
    207.             (fbSize / 1048576.0) / ((double) average / 1000000.0));
    208.     printf (" Max. FPS: %.03f fps\n\n",
    209.             1000000.0 / (double) average);

    210.     /* Clear the framebuffer back to black again: */
    211.     memset (fb, 0, fbSize);
    212. }

    213. int
    214. main (int argc, char **argv)
    215. {
    216.     const char *devfile = "/dev/fb0";
    217.     long int screensize = 0;
    218.     int fbFd = 0;


    219.     /* Open the file for reading and writing */
    220.     fbFd = open (devfile, O_RDWR);
    221.     if (fbFd == -1)
    222.     {
    223.         perror ("Error: cannot open framebuffer device");
    224.         exit (1);
    225.     }

    226.     //获取finfo信息并显示
    227.     if (ioctl (fbFd, FBIOGET_FSCREENINFO, &finfo) == -1)
    228.     {
    229.         perror ("Error reading fixed information");
    230.         exit (2);
    231.     }
    232.     printFixedInfo ();
    233.     //获取vinfo信息并显示
    234.     if (ioctl (fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1)
    235.     {
    236.         perror ("Error reading variable information");
    237.         exit (3);
    238.     }
    239.     printVariableInfo ();

    240.     /* Figure out the size of the screen in bytes */
    241.     screensize = finfo.smem_len;

    242.     /* Map the device to memory */
    243.     frameBuffer =
    244.         (char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
    245.                      fbFd, 0);
    246.     if (frameBuffer == MAP_FAILED)
    247.     {
    248.         perror ("Error: Failed to map framebuffer device to memory");
    249.         exit (4);
    250.     }

    251.     //测试virt fb的性能
    252.     performSpeedTest (frameBuffer, screensize);

    253.     printf ("Will draw 3 rectangles on the screen,\n"
    254.             "they should be colored red, green and blue (in that order).\n");
    255.     drawRect (vinfo.xres / 8, vinfo.yres / 8,
    256.              vinfo.xres / 4, vinfo.yres / 4, 0xffff0000);
    257.     drawRect (vinfo.xres * 3 / 8, vinfo.yres * 3 / 8,
    258.              vinfo.xres / 4, vinfo.yres / 4, 0xff00ff00);
    259.     drawRect (vinfo.xres * 5 / 8, vinfo.yres * 5 / 8,
    260.              vinfo.xres / 4, vinfo.yres / 4, 0xff0000ff);

    261.     sleep (5);
    262.     printf (" Done.\n");

    263.     munmap (frameBuffer, screensize);    //解除内存映射,与mmap对应

    264.     close (fbFd);
    265.     return 0;
    266. }
    复制代码

    论坛徽章:
    0
    6 [报告]
    发表于 2010-04-24 22:44 |显示全部楼层
    很不错的文章啊,感谢LZ分享。
    不知道有没有和这个类似的讲overlay的文章呢?
    kartwall 发表于 2010-04-24 18:07



        没有做过这方面的工作。linux内核中集成了很多驱动,估计可以找到参考吧。有这方面的文章方便一点,没的话结合源码datasheet来看,也完全可以应付了

    论坛徽章:
    0
    7 [报告]
    发表于 2010-11-24 15:35 |显示全部楼层
    回复 30# smalloc


        smalloc兄研究问题很仔细,佩服

    论坛徽章:
    0
    8 [报告]
    发表于 2011-07-24 20:39 |显示全部楼层
    哎,视频方面很久没做了,都忘记光了。话说回来,以前做得也只是一点点皮毛。
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP