Chinaunix首页 | 论坛 | 博客
  • 博客访问: 149879
  • 博文数量: 54
  • 博客积分: 2517
  • 博客等级: 少校
  • 技术积分: 540
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-13 18:52
文章分类
文章存档

2011年(2)

2010年(11)

2009年(41)

我的朋友

分类: LINUX

2009-09-16 21:34:05

-----------------------------------------------------------------------------

例子实现了直接写屏的功能,即把屏幕清空(变黑),程序的流程大致为:打开一个FrameBuffer设备;通过mmap调用把显卡的物理内存空间映射到用户空间;通过映射关系直接写内存。

 

头文件

fbtools.h


#ifndef _FBTOOLS_H_

#define _FBTOOLS_H_

 

#include

 

//a framebuffer device structure;

typedef struct fbdev{

               int fb;

               unsigned long fb_mem_offset;

               unsigned long fb_mem;

               struct fb_fix_screeninfo fb_fix;

               struct fb_var_screeninfo fb_var;

               char dev[20];

} FBDEV, *PFBDEV;

 

//open & init a frame buffer

//to use this function,

//you must set FBDEV.dev="/dev/fb0"

//or "/dev/fbX"

//it's your frame buffer.

int fb_open(PFBDEV pFbdev);

 

//close a frame buffer

int fb_close(PFBDEV pFbdev);

 

//get display depth

int get_display_depth(PFBDEV pFbdev);

 

 

//full screen clear

void fb_memset(void *addr, int c, size_t len);

 

#endif


 

测试文件,其中深颜色的注释部分为在我机器上测得的结果

fbtools.c

代码:


 

#include

#include

#include

#include

#include

#include

#include

#include

 

#include "fbtools.h"

 

#define TRUE          1

#define FALSE         0

#define MAX(x,y)        ((x)>(y)?(x):(y))

#define MIN(x,y)        ((x)<(y)?(x):(y))

 

//open & init a frame buffer

int fb_open(PFBDEV pFbdev)

{

               pFbdev->fb = open(pFbdev->dev, O_RDWR);// pFbdev->fb==3

               if(pFbdev->fb < 0)

               {

                               printf("Error opening %s: %m. Check kernel config\n", pFbdev->dev);

                               return FALSE;

               }

               if (-1 == ioctl(pFbdev->fb,FBIOGET_VSCREENINFO,&(pFbdev->fb_var)))

               {

                               printf("ioctl FBIOGET_VSCREENINFO\n");

                               return FALSE;

               }

               if (-1 == ioctl(pFbdev->fb,FBIOGET_FSCREENINFO,&(pFbdev->fb_fix)))

               {

                               printf("ioctl FBIOGET_FSCREENINFO\n");

                               return FALSE;

               }

              

               //map physics address to virtual address

               // pFbdev->fb_fix.smem_start=f0000000

               pFbdev->fb_mem_offset = (unsigned long)(pFbdev->fb_fix.smem_start) & (~PAGE_MASK);

// pFbdev->fb_fix.smem_len=100 0000 pFbdev->fb_mem_offset=0

// pFbdev->fb_mem =0

               pFbdev->fb_mem = (unsigned long int)mmap(NULL, pFbdev->fb_fix.smem_len +

                                          pFbdev->fb_mem_offset,

                               PROT_READ | PROT_WRITE, MAP_SHARED, pFbdev->fb, 0);

               if (-1L == (long) pFbdev->fb_mem)

               {

                               printf("mmap error! mem:%d offset:%d\n", pFbdev->fb_mem,

                                                      pFbdev->fb_mem_offset);

                               return FALSE;

               }

              

               return TRUE;

}

 

//close frame buffer

int fb_close(PFBDEV pFbdev)

{

               close(pFbdev->fb);

               pFbdev->fb=-1;

}

 

//get display depth

int get_display_depth(PFBDEV pFbdev);

{

               if(pFbdev->fb<=0)

               {

                               printf("fb device not open, open it first\n");

                               return FALSE;

               }

               return pFbdev->fb_var.bits_per_pixel;

}

 

//full screen clear

void fb_memset (void *addr, int c, size_t len)

{

    memset(addr, c, len);

}

 

//use by test

#define DEBUG

#ifdef DEBUG

main()

{

               FBDEV fbdev;

               memset(&fbdev, 0, sizeof(FBDEV));

               strcpy(fbdev.dev, "/dev/fb0");

               if(fb_open(&fbdev)==FALSE)

               {

                               printf("open frame buffer error\n");

                               return;

               }

               //注意,下面一行有bug

               fb_memset(fbdev.fb_mem + fbdev.fb_mem_offset, 0, fbdev.fb_fix.smem_len);

              

               fb_close(&fbdev);

}

#endif


编译

如果对上述代码直接进行编译的话,是不能成功的,即会出现类似下面的编译错误

#gcc –o fbtools fbtools.c

fbtools.c: In function `main`

fbtools.c:89:warning:passing arg 1 of `fb_memset` makes pointer from integer without a cast

 

对有问题的fbtools.c中的第89行代码(即加粗的有注释的那一行)进行如下操作

修改为:

fb_memset((void *)(fbdev.fb_mem+fbdev.fb_mem_offset), 0, fbdev.fb_fix.smem_len);

或者

unsigned long temp;

temp= fbdev.fb_mem+fbdev.fb_mem_offset;

fb_memset((void *)temp, 0, fbdev.fb_fix.smem_len);

 

可以成功编译成功

 

而修改为:

fb_memset((&)(fbdev.fb_mem+fbdev.fb_mem_offset), 0, fbdev.fb_fix.smem_len);

或者

unsigned long temp;

temp= fbdev.fb_mem+fbdev.fb_mem_offset;

fb_memset((&)temp, 0, fbdev.fb_fix.smem_len);

 

会输出:段错误

 

分析

函数原形为:void fb_memset (void *addr, int c, size_t len)

fbtools.c:89调用时传递的参数为:

fb_memset(fbdev.fb_mem+fbdev.fb_mem_offset, 0, fbdev.fb_fix.smem_len);

fbdev.fb_memfbdev.fb_mem_offset都是unsigned long类型的变量,它们的计算结果保存在一个临时的栈空间,传递调用时,其临时的地址是不能够传递到被调用的函数的,所以编译是同不过的。具体的可以参考内存分配的相关知识,记得《effective c++》一书里讲的很详细,可以参考。

至于修改后的:

fb_memset((&)temp, 0, fbdev.fb_fix.smem_len);

编译出现段错误,也是很好理解的,因为(&)temp不等于(void *)temp,也不等于

(void *)(fbdev.fb_mem+fbdev.fb_mem_offset),具体原因读者可以对照《effective c++》思考。


本文主要介绍了directfbrc文件的使用及参数的详细说明,在directfb应用程序启动做初始化阶段,都会去试图读取该文件。

摘要:
本文主要介绍了directfbrc文件的使用及参数的详细说明,在directfb应用程序启动做初始化阶段,都会去试图读取该文件。
---------------------------------------------------------------------------------------------------------------------
声明:
      
此文为原创,欢迎转载,转载请保留如下信息
      
作者:聂飞(afreez
      
联系方式:afreez@sina.com (欢迎与作者交流)
      
初次发布时间:2006-06-06
     
不经本人同意,不得用语商业或赢利性质目的,否则,作者有权追究相关责任!
-----------------------------------------------------------------------------

directfbrcDirectFB配置文件。它被所有的DirectFB应用程序在启动时读取,有两个这样的文件,一个是存放在/etc/direcfbrc,是个全局的,另一个是存放在$HOME/.directfbrc,它是个局部的,可以覆盖系统的设置。

需要注意的是,这两个文件都不是默认存在的,是需要你自己建立的,不要象我一样,刚开始的时候到处找也没有找到,呵呵。

directfbrc使用的参数也可以在命令行里传递给DirectFB应用程序,只需要加上前缀:--dfb:

 

相关语法:

directfbrc文件每一行包含一个变量。注释行以井号“#”开始,一直到行尾。空行被忽略。

许多参数只是一种开关,控制着一些特性的开/关。这些开关选项有一个no-变量,可以关闭相应的特性。下面介绍一些实用的参数和一些默认的参数。

 

参数:

以下参数可以在directfbrc文件中设定

system=

       设定使用的图形系统。默认使用Linux frame buffer (fbdev),但你也可以在SDLsdl)上运行DirectFB应用程序。其它的系统在将来可能会被扩展近来。

fbdev=

打开指定的frame buffer 设备,而不是默认的/dev/fb0

mode=x

设定默认的屏幕显示。如果不设定,DirectFB 将使用/etc/fb.modes 的第一个设定值。一些frame buffer 设备( vesafb) 不支持模式切换,而只能使用启动时设定的值。

depth=

使用二进制位数设置每像素默认的像素深度。如果没有指定,DirectFB将使用/etc/fb.modes 里面的第一个指定的深度值。DirectFB 支持8, 15, 16, 24 32位的颜色深度(color depths),这些值依赖于你使用的frame buffer设备是否支持。一些frame buffer 设备(如: vesafb) 根本就不支持模式切换,只能使用在启动时设定的像素深度值。

pixelformat=

设置默认的像素格式。和上面描述的深度参数类似但允许更精细的控制。Pixelformat的值可以为LUT8, RGB332, RGB16, RGB24RGB32。一些设备可能还支持更奇怪的A8, ALUT44, ARGB, ARGB1555, I420, UYVY, YUY2 YV12像素格式。

session=

选择被添加或创建的多应用程序。开始为0,如果强行设置为负值,则使用一个可用的最小值。设定的值将覆盖环境变量“DIRECTFB_SESSION”的值。

primary-layer=

选定哪一个层为“主层”(primary layer),默认的是第一个。查看‘dfbinfo’可以找到你的硬件支持的层列表。

tmpfs=

使用给定的文件夹(tmpfs挂载点)来多应用程序模式下创建共享内存文件。这个选项只在自动检测失败或者渴望非tmpfs存储时才有用。

memcpy=

使用这个选项,对memcpy()程序(routines)的探测会被忽略,节省了不少启动时间。传递“help”参数可以看到一系列的可能值。

quiet

禁止从DirectFB 控制台(console)输出。只显示错误信息。

[no-]banner

启动时使输出DirectFB 标志(banner)有效。默认有效。

[no-]debug

使debug输出有效。默认有效,但是除非你编译DirectFB 时支持debug选项,否则,你不会不看到任何错误输出。

force-windowed

强制主表面(primary surface)为一个窗口。这样可以使设计成全屏显示的应用程序在一个窗口上运行。

force-desktop

强制使主表面(primary surface)成为桌面的后台表面(background surface)。

[no-]hardware

置硬件加速为有效。默认会自动探测硬件加速。如果你置它为无效,则显卡驱动虽然也会被加载并可以访问其它的显示层(如果有的话),但是,所有的图形操作将被软件来渲染(renderer)。

[no-]sync

初始化DirectFB 之前清空所有的硬盘缓冲区(disk buffers) 。当你工作环境为实验性的设备驱动和预计会出现冲突(crashes)时比较有用。默认此功能为无效。

[no-]mmx

选相no-mmx使得即使检测到有MMX的支持也不能使用MMX程序(routines)。如果提供了MMX并在编译时加入了MMX的支持,默认该选相有效。

[no-]argb-font

ARGB面载入字的轮廓(glyphs),而不是使用A8面(alpha masks)。该设置使用了更多的内存,但是一些显卡在使用A8面时会出现一些诡异现象。如果你的字体看起来比较奇怪,试试该选项。

[no-]a1-font

A1平面载入字的轮廓(glyphs),而不是使用A8平面(alpha masks)。如果图形驱动不支持彩色+混合平移(blit,译者注,blit此处翻译成平移,具体的含义见附录),该选项可以加速字体渲染,但会影响质量。一般情况下你根本不需要使用该选项,因为基于A8字体的软件已经是高度优化和足够快了。

[no-]sighandler

默认情况下,DirectFB 为一些信号量(signal)安装了一个可以使应用程序退出的信号量句柄(handler)。这个信号量句柄试图在退出应用程序前解除初始化的DirectFB 引擎。使用该选项可以开/关此特性。

dont-catch=[[,]...]

和上面对sighandler 选项描述类似。使用该选项你可以对不能使用该方式被处理的信号量列出一个详细的清单。

[no-]deinit-check

默认情况下,DirectFB在退出时会检查所有已释放所分配的资源,如果没有,它将在应用程序退出后释放之。该选项可以开/关此功能。

block-all-signals

该选项可以阻塞所有的信号量,对DirectFB daemons 有用(DirectFB master应用程序除了是一个master外,什么也不做)。

[no-]vt-switch

默认情况下,DirectFB会分配一个新的虚拟终端并转向使用它。

[no-]vt-switching

可以使用++来切换虚拟终端。这是一个实验特性,经常无效,你看着办吧。

[no-]graphics-vt

使虚拟终端转为图形模式。有如下优点:当DirectFB 应用程序运行时,内核的消息不会在屏幕上显示。

[no-]motion-compression

DirectFB常常压缩(compresse)鼠标移动事件。也就是说,一系列的鼠标移动事件被看作一个简单的鼠标移动事件。这样可以达到更快的响应但是鼠标处理的精确度会受到影响。

mouse-protocol=

为一个串口鼠标指定使用的协议。以下的协议被支持:

MS 使用微软鼠标协议的两个按钮的鼠标;

MS3使用扩展的微软鼠标协议的三按钮鼠标;

MouseMan使用一种Logitech开发的另一种扩展的微软鼠标协议的三按钮的鼠标;

MouseSystems 广泛使用的三按钮鼠标。

串口鼠标所使用的协议的详细信息可参考相关资料。

[no-]lefty

切换鼠标左右按键,对“左撇子”(^_^)比较有用。

[no-]capslock-meta

CapsLock 键映射到Meta。对建在WM的用户有用,因为键盘上没有Meta键(例如Window 键)。

[no-]cursor

默认情况下,DirectFB 在使用窗口时显示一个鼠标箭头。该选项允许彻底关闭鼠标箭头。即使在应用程序里也不能让它再出现。

disable-module=

禁止该模块的载入。模块的名字为文件名,但不能带有libdirectfb 前缀也不能是其扩展(例如,若文件名为keyboard,则键盘输入模块载入被禁止)。

bg-none

使背景处理完全无效。不要设置给选项,否则鼠标和窗口移动时会在背景留下难看的痕迹。

bg-color=AARRGGBB

控制背景的颜色。颜色的值为十六进制值。默认的alpha值为完全不透明并可能被忽略。例如,设定背景色为红紫色(magenta),可以使用bg-color=FF00FF

bg-image=

使用给定的文件中的图象充填背景。图象会被伸缩(stretch)以适应屏幕的尺寸。

bg-tile=

类似bg-image,这里使用图象的图快(tile)方式在屏幕的尺寸显示,而不是伸缩方式。

[no-]translucent-windows

默认情况下,DirectFB 窗口可能是半透明的。如果你使该选项无效,则窗口会被强制为完全不透明或者是全透明。当你的显卡不支持alpha 半透明图快(alpha-transparent blit)时,该选项比较有用。

videoram-limit=

限制DirectFB 使用的视频RAM。视频RAM大小的单位为K字节数。

matrox-tv-standard=[pal|ntsc]

控制由Matrox 卡的TV输出产生的信号。

[no-]matrox-sgram

一些老的Matrox G400 卡有SGRAM 并且如果设定该选项,一些图形操作在这些卡上执行相当快。如果你的卡上没有SGRAM,不要试图选中该选项,否则,你不得不重起。

[no-]matrox-crtc2

如果你有个双重的head G400/G450/G550,你可是使用该选项利用第二个head驱动附加层。

screenshot-dir=

如果选定该选项,当你按下 键,DirectFB 将把屏幕的内容以PPM格式放到这个指定的目录。

window-surface-policy=

控制窗口平面存放的位置。的值可以是:

auto DirectFB依据硬件特性自动判断,默认为该选项;

videohigh 以高优先级方式切换(swap)系统/视频内存;

videolow  以低优先级方式切换(swap)系统/视频内存;

systemonly 窗口平面保存在系统内存中;

videoonly 窗口平面保存在视频内存中。

desktop-buffer-mode=

控制桌面缓冲区模式。无论何时,窗口在移动、打开、关闭、调整大小或者变换内容,DirectFB 将在受影响的范围内重新合成窗口堆栈,这是通过和平移(blit)在该范围的窗口一起来完成的。不通明窗口被直接平移,而半透明的窗口则使用alpha 混合或颜色键来平移。如果有后端缓冲区(back buffer)的话,合成是不可见的,因为只有最终的结果会被拷贝到前端缓冲区(front buffer)。如果没有后端缓冲区,合成的每一步都是可见的,这将导致明显的闪烁,除非所有的窗口都是非透明的。

的可选值有:

auto DirectFB依据硬件特性来判断,为默认值。如果硬件支持简单blit(从后端向前端缓冲区中拷贝)操作,DirectFB会在视频缓冲区中选取一个后端缓冲区。如果没有加速功能,会在系统内存中开辟一个后端缓冲区,因为这样软件里的alpha混合合成操作可以执行地更好,并可以避免在结果已经拷贝到前端缓冲区中的情况下,再重新从视频缓冲区中读取。

backsystem 在系统内存中开辟一个后端缓冲区。如果你的硬件支持简单blitting但却没有alpha混合,这是推荐选择,你将得到许多alpha混合窗口。

backvideo 在视频内存中分配前端和后端缓冲区。该值特别不建议设定,因为如果blit被加速的话,‘auto’模式下会选择该值。没有加速的blit操作,该值不推荐使用。

frontonly 没有后端缓冲区。如果你仅仅使用不透明窗口并且不使用任何颜色键,这是一个最佳选择。

vsync-after

flip操作后等待垂直折回(vertical retrace)。默认情况下在做flip操作前等待。

vsync-none

对垂直折回(vertical retrace)关闭polling操作。

 

例子

下面的例子说明了怎么在命令行模式下,把上面介绍的参数传递给DirectFB应用程序。

df_neo --dfb:no-hardware

以没有硬件加速的方式开始运行df_neo 

df_neo --dfb:help

列出可以传递给df-neo的所有可选参数。

 

附录:

说明,这里以下的部分是从网上摘录的,仅供参考!

Blit操作相关解释(从网络摘抄整理,详见参考文献,即reference):

基本含义:

其意义是将一个平面的一部分或全部图象整块从这个平面复制到另一个平面;

BlitCopyBox的区别:

Blit 用于在不同的屏幕设备(物理的或者内存的)之间拷贝一块像素点,CopyBox则用于在同一屏幕上实现区域像素的拷贝。如果使用的是线性模式,Blit的 实现非常简单,直接memcpy 就可以了,而CopyBox 为了防止覆盖问题,必须根据不同的情况,采用不同的拷贝方式,比如从底到顶底拷贝,当新老位置在同一水平位置并且重复时,则需要利用缓冲间接拷贝。如果使用平面显示模式,这里就比较复杂了。因为内存设备总是采用线性模式的,所以就要判断是物理设备还是内存设备,再分别处理。这也大大地增加了fbvga16 实现的代码。

Blit与显示内存的有效利用

新的 GAL 接口能够有效利用显示卡上的显示内存,并充分利用硬件加速功能。我们知道,现在显示卡一般具有 4M 以上的显示内存,而一般的显示模式下,不会占用所有的显示内存。比如在显示模式为 1204x768x32bpp 时,一屏象素所占用的内存为 3M,还有 1M 的内存可供应用程序使用。因此,新的GAL引擎能够管理这部分未被使用的显示内存,并分配给应用程序使用。这样,一方面可以节省系统内存的使用,另一方面,可以充分利用显示卡提供的加速功能,在显示内存的两个不同内存区域之间进行快速的位块操作,也就是常说的 Blitting

Blitting 操作与嵌入式汇编代码优化处理

在上层 GDI 接口在建立内存 DC 设备时,将首先在显示内存上分配内存,如果失败,才会考虑使用系统内存。这样,如果 GAL 引擎提供了硬件加速功能,两个不同 DC 设备之间的 Blitting 操作(即 GDI 函数 BitBlt),将以最快的速度运行。更进一步,如果硬件支持透明或 Alpha 混和功能,则透明的或者 Alpha 混和的 Blitting 操作也将以最快的速度运行。新的 GAL 接口能够根据底层引擎的加速能力自动利用这些硬件加速功能。目前支持的硬件加速能力主要有:矩形填充,普通的 Blitting 操作,透明、Alpha 混和的 Blitting 操作等。当然,如果硬件不支持这些加速功能,新的 GAL 接口也能够通过软件实现这些功能。目前通过 GAL FrameBuffer 引擎提供上述硬件加速功能的显卡有:Matrox3dfx 等。

    在通过软件实现透明或混和的 DC Blitting 操作时,新的 GAL 接口利用了两种有效的优化措施:

i386 平台上,充分利用嵌入式汇编代码进行优化处理;比如在处理 32 位色模式下的普通 Blitting 操作时,在利用普通的 C 库函数,即 memcpy 进行位块复制时,由于 memcpy 函数是以字节为单位进行复制的,从而无法利用 32 CPU 32 位字的处理能力,为此,可以使用嵌入式汇编,并以 32 位字为单位进行复制,这将大大提高 Bliting 操作的处理速度。

对源 DC 进行 RLERun Length Encoding)编码,从而对象素的处理数量最小化。RLE 可以看成是一种图象压缩算法,Windows BMP 文件就利用了这种算法。RLE 是按水平扫描线进行压缩编码处理的。在一条扫描线上,如果有大量相同的象素,则不会保存这些象素点,而是首先保存具有相同象素点的数目,然后保存这些象素点的值。这样,在进行透明或者混和的 Blitting 操作时,可以大大降低逐点运算带来的速度损失。但是,如果在最坏的情况下,比如所有水平扫描线上的象素点都具有和相邻点不同的象素值,则 RLE 编码反而会增加象素的存储空间(最坏的情况是原有空间的两倍),同时也会降低 Blitting 操作的速度。因此是否使用 RLE 编码,要根据情况而定。新的 GDI 接口在指定源 DC 的透明和 Alpha 通道值时,可以指定是否使用 RLE 编码。

 

Reference:

1Man page of DIRECTFBRC 一篇英文的参数说明档;

see

2MiniGUI blit的解释;see

3DirectX6.0程序员手册,其中,有一点对blit的解释;

see  

 

阅读(1737) | 评论(0) | 转发(0) |
0

上一篇:DirectFB初探2

下一篇:pkg-config应用

给主人留下些什么吧!~~