Chinaunix首页 | 论坛 | 博客
  • 博客访问: 465556
  • 博文数量: 150
  • 博客积分: 2706
  • 博客等级: 少校
  • 技术积分: 1200
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-09 11:41
文章分类

全部博文(150)

文章存档

2012年(7)

2011年(6)

2010年(68)

2009年(69)

我的朋友

分类:

2010-03-26 13:12:03

1.概述

根据目前STB的媒体表现形式不足和将来的功能扩展需求,需要有一套稳定、灵活的显示设备、输入设备适配层。 DirectFB(以下简称DFB)是针对嵌入式系统资源和性能特点而设计的一套图形库。我们在这里对DFBDavinci平台上的可用性做一次分析。

分析的主要内容有:

1)      代码的编译选项

2)      图形库主要特性

3)      典型应用程序启动、画图显示过程分析

4)      分析DFBDavinci平台上应用的可行性

2.编译选项

./configure  CC=arm_v5t_le-gcc CXX=arm_v5t_le-g++ AR=arm_v5t_le-ar  RANLIB=arm_v5t_le-ranlib LD=arm_v5t_le-ld CFLAGS="-O2 -ffast-math -pipe" CPPFLAGS=-I/home/cnc/devkit/arm/v5t_le/target/usr/include   LDFLAGS="-L/home/cnc/devkit/arm/v5t_le/target/lib -L/home/cnc/devkit/arm/v5t_le/target/usr/lib"  --host=arm-linux --build=i386 --prefix=/home/cnc/root-nfs/usr/local  --exec-prefix=/usr/local --enable-debug  --enable-trace    --enable-static --enable-multi --enable-fbdev --without-tools   --with-gfxdrivers=davinci

上面的编译选项中:   

--enable-multi   允许多进程间共享显示设备(下面的分析都是基于此编译条件)
        --enable-debug   
允许调试信息与断言
        --enable-trace   
允许运行时堆栈跟踪

 

DFB图形库编译安装成功后,我们需要编写DFB在目标系统上的运行配置。

directfbrcDFB图形库启动的配置文件,配置方式分为:

系统级配置:a system-wide one stored in /etc/directfbrc

用户级配置:a per-user $HOME/.directfbrc which may override system settings.

也可以通过应用程序(basename of argv[0]))传入:/etc/directfbrc.$0 $HOME/.directfbrc.$0

下面是配置文件的具体示例,更详细的配置方式请参阅文档Man page of DIRECTFBRC.mht

system=fbdev

fbdev=/dev/fb0

mode=720x576

depth=16

pixelformat=RGB16

 

systems指定显示系统接口,目前可选接口有:

dvevm:直接操作硬件地址空间适配层代码

fbdev: 输出到frame buffer

osx:   输出到mac os上。

vnc 输出到Virtual Network Computing(类似于微软远程桌面的一个协议)。

x11 输出到X Window

sdl  输出到Simple DirectMedia Layer

这里我们使用framebuffer接口。

mode指定显示设备的分辨率;

depth为像素位数;

pixelformat指定显示设备像素格式。

 

 

3.DFB图形库关键模块-fusion

在介绍DFB之前先介绍一下DFB多进程共享同一显示资源的核心模块fusion。在传统的DFB应用中,所有的应用程序都在一个进程中,在性能上,有一些优势,然而一个应用程序不稳定会造成整个系统的不稳定。若采用C/S模型,无疑是重蹈X Widnow的覆辙,会丧失性能上的优势。所以DirectFB采用了另外一种方式,与C/S相区别,称之为主从模型(Master/Slave)。它加了一个称之为fusion的内核模块。Fusion是熔化的意思,多个应用程序在不同的进程空间里,通过这个内核模块通信,在这里,一切都溶为一体。Master应用程序负责初始化一个称为竟技场(Arena)的东西,其它Slave应用程序可以加入(join)或者退出(leave)竟技场。当Master退出时,则其它所有Slave都必须退出。Fusion里采用了Reactor模式,每个应用程序可以通过ioctlreactor注册事件处理器,当有事件发生时,reactor会把事件写入到所注册了的应用程序的fusion文件描述符时,之后应用程序可以从fusion文件描述符里读取到事件数据。当然,应用程序也可以通过ioctl发送事件给其它应用程序,reactor也会把事件分发给其它应用程序。

 

 

/*关于fusion的调用函数定义都是通过FUSION_OBJECT_METHODS这个宏定义实现的*/

消息分发线程的创建

DirectFBCreate

fusion_enter>>>Master应用程序初始化或join Arena挂在/dev/fusionN

direct_thread_create( DTT_MESSAGING, fusion_dispatch_loop, world, "Fusion Dispatch" );

fusion_dispatch_loop>>>启动消息分发线程

 

以注册Surface对象的Flip事件为例说明fusion注册事件流程

IDirectFB_CreateSurface>>>创建一个surface对象

IDirectFBSurface_Construct>>>

dfb_surface_attach( surface,IDirectFBSurface_listener, thiz, &data->reaction ); >>注册surface

                                                                                                        listener

fusion_reactor_attach>>注册surface 相关的回调函数

ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_ATTACH, &attach )

发送Surface Flip事件

dfb_surface_flip( data->surface, false );>>> 改变surface buffer index

dfb_surface_notify( surface, CSNF_FLIP );>>>

dfb_surface_dispatch( surface, ¬ification, dfb_surface_globals );>>> 通过fusion通知进行surface_listener flip操作

 

 

 

下面以触摸屏为例介绍笔点事件的过程:

1)初始化时,driver_open_device创建一个进程,挂在/dev/input/event0上,等待笔点事件。

2)初始化时,应用程序创建另外一个线程,挂在/dev/fusionN(不同的应用程序N值不同)上。

3) 当有笔点事件时,通过函数调用dfb_input_dispatch-->fusion_reactor_dispatch->ioctl (FUSION_REACTOR_DISPATCH)把消息丢给内核模块。

4) 内核模块中的Reactor把事件数据写入到各个所注册的事件处理器的/dev/fusionN里。

5) 应用程序从/dev/fusionN文件中取得事件数据,并调用应用程序内部的reactor处理函数,一般是IDirectFBEventBuffer_InputReact/IDirectFBEventBuffer_WindowReact两个函数。

6) 然后,在IDirectFBEventBuffer_InputReact/IDirectFBEventBuffer_WindowReact两个函数中,调用IDirectFBEventBuffer_AddItem把事件加入到窗口的事件队列中。

7) 在应用程序的主线程中,就可以通过调用窗口的GetEvent函数从事件队列中获取事件了,最后,把获取的事件分发到各个窗口事件处理函数中。

 

3.通过调试信息来分析DFB核的启动过程:

所有基于DFB显示的应用程序运行前都需要调用下面两个接口函数:

DirectFBInitDirectFBCreate

DirectFBInit中通过读取DFB配置文件、DFB环境变量,解析入口参数来初始化全局配置。

DirectFBCreate完成整个图形库创建使用前资源申请、核心对象创建的工作。

 

我们用下面的log来跟踪DFB Core的创建过程:(蓝色为解释,黑色为打印的log

=======================|  DirectFB 1.1.1  |=======================

          (c) 2001-2007  The DirectFB Organization (directfb.org)

          (c) 2000-2004  Convergence (integrated media) GmbH

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

//指示当前DFB图形库为支持多进程共享方式,且通过dfb_system_lookup/usr/local/lib/directfb-1.1.1/system中遍历加载图形接口库,找到配置文件中指定的system

(*) DirectFB/Core: Multi Application Core. (2008-02-28 06:31) [ DEBUG ][ TRACE ]

 

//dfb_core_create>>>fusion_enter>>>

//fusion_enter 解释为Enters a fusion world by joining or creating it.,说明每当一个进程调用DFB图形库都会获取一个world index,打开对性的Fusion Kernel Device/dev/fusion(0~8)

,且同时支持的最大数量为FUSION_MAX_WORLDS=8

//提示目前内核版本存在MADV_REMOVE漏洞

(*) Fusion/SHM: NOT using MADV_REMOVE (2.6.10.0 < 2.6.19.2)! [0x02060a00]

 

//dfb_core_create>>>fusion_enter>>>/* Start the dispatcher thread. */

                       direct_thread_create( DTT_MESSAGING,fusion_dispatch_loop,world, "Fusion Dispatch" );启动消息接收处理线程,负责接收来自其他进程的消息

(*) Direct/Thread: Running 'Fusion Dispatch' (MESSAGING, 1297)...

 

//dfb_core_create>>>dfb_system_thread_init>>>system_funcs->ThreadInit()(fbdev.c-system_initialize)>>>dfb_vt_initialize>>>vt_init_switching

(*) Direct/Thread: Running 'VT Switcher' (CRITICAL, 1307)...

 

//下面以加载鼠标为例说明驱动Probe过程,Keyboard ,显卡MMX 过程都类同

//在循环打开动态库的同时完成下面过程DFB_INPUT_DRIVER( ps2mouse )>>>driver_open_device>>>

/* start input thread */     data->thread = direct_thread_create( DTT_INPUT, linux_input_EventThread, data, "Linux Input" );

(*) Direct/Thread: Running 'PS/2 Input' (INPUT, 1321)...

(*) DirectFB/Input: IMPS/2 Mouse 1.0 (directfb.org)

(*) Direct/Thread: Running 'Keyboard Input' (INPUT, 1322)...

(*) DirectFB/Input: Keyboard 0.9 (directfb.org)

//Generic 软件渲染

(*) DirectFB/Graphics: Generic Software Rasterizer 0.6 (directfb.org)

//创建窗口管理器

(*) DirectFB/Core/WM: Default 0.3 (directfb.org)

 

//以devfb为例说明分辨率、像素格式的检测过程

1.注册devfb region测试函数:

fbdev.c system_initialize

>>>/* Register primary layer functions */

     dfb_layers_register( screen, NULL, &primaryLayerFuncs );

2.完成测试过程:

DirectFBCreate>>>IDirectFB_Construct>>>

if (dfb_core_is_master( core )) {

          ret = InitLayers( thiz, data );

>>>dfb_layer_context_test_configuration

>>> funcs = layer->funcs;

    /* Test the region configuration. */

     if (region_config.buffermode == DLBM_WINDOWS) {}

     else{  /* Let the driver examine the modified configuration. */

          ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data,

                                   ®ion_config, &failed );

     }

(*) FBDev/Mode: Testing 720x576 RGB16

(*) FBDev/Mode: Preparing switch to 720x576 RGB16

(*) FBDev/Mode: Testing 720x576 RGB16

(*) FBDev/Mode: Preparing switch to 720x576 RGB16

(*) FBDev/Mode: Testing 720x576 RGB16

(*) FBDev/Mode: Preparing switch to 720x576 RGB16

(*) FBDev/Mode: Testing 720x576 RGB16

(*) FBDev/Mode: Preparing switch to 720x576 RGB16

(*) FBDev/Mode: Testing 720x576 RGB16

(*) FBDev/Mode: Preparing switch to 720x576 RGB16

 

(*) FBDev/Surface: Allocated 720x576 16bit RGB16 buffer at offset 0 and pitch 1440.

(*) FBDev/Mode: (Post)Setting 720x576 RGB16

(*) FBDev/Mode: Switched to 720x576 (720x576) at 16 bit RGB16 (wanted RGB16).

(*) FBDev/Mode: Testing 720x576 RGB16

(*) FBDev/Mode: Preparing switch to 720x576 RGB16

(*) FBDev/Mode: (Post)Setting 720x576 RGB16

-------------------------woods---------df_fire---DirectFBCreate success

4.DFB画图流程

4.1在分析画图流程前先罗列一下DFB中关于图形相关名词

Blitting

Blitting是只图像数据的拷贝过程。举一个最简单的例子就是当两个Surface有相同的大小,颜色深度和像素格式时,Blitting 其中一个Surface 到另一个Surface。在这个过程中内存只被复制而没有被处理(就像复制其他任何类型的数据一样)。除此之外还有更高级的带alpha通道的blitting或者带不同像素格转换功能的blitting。许多图形显卡是由硬件Blitting来完成多种格式数据的传输和操作。一般来讲在完成Blitting操作后,我们即可在显示设备上看到要显示的内容。

Surface

Surface 是图像以一种具体的像素格式被保存的一块内存区域。一个Surface

可以位于显存或系统内存中。可以在一个Surface上进行画图操作或者把一个Surface

Blitting到另一个上。

在全屏模式下时,屏幕中的可视区称为Surface,所以可以直接在屏幕的可

视区完成图形操作。

为了避免闪烁问题,每个Surface 都可以选择双缓冲,图形操作将首先在辅助缓冲区中执行然后采用Flip操作将其显示到可视区域。

SubSurface

SubSurface使用和Surface相同的接口。它代表父类Surface的一个区域并且没有

为自己分配任何系统或显存空间。

Layer

针对不同的显卡而言可能存在有一个或者多个显示层。一个标准的PC显卡只有一个层,但是对于嵌入式设备而言可能不只一个,比如TI Davinci平台的Video Processing Back End就包含4个硬件Layer,每个Layer都有独立的显存和显示控制特性。常用的硬件alpha blend也多半都是基于这些硬件Layer完成的。其中真对STB应用,有一个比较特殊的LayerVideo层,一般情况下Video层都是位于底层且不支持透明,有的还支持硬件缩放,YUVRGB颜色空间转换功能。真对硬件Layer的特点, DFB相应的实现了一些型号的显卡驱动。

 

Window / Windowstack

为了达到多显示对象的独立控制,DFB设计了一个Window管理器对某一个Layer上显示内容进行管理。每个Window有独立的Surface进行画图操作,Window之间可以有重叠、聚焦、透明处理、获取事件等操作,增加了应用程序显示的多样性和灵活性。多个Window组成了一个WindowStack

4.2下图所示为DFB类间简单逻辑关系

screenàN Layer    (Davinci上为2Video Layer 2OSD Layer)

1 Layer à N Window

Window à N  Region

以上的N都是有最大值的,这里只代表多个的意思。

 

4.2以在Davinci平台的OSD Layer上的显示为例,分析DFB的画图流程:

 

情况1:如果我们不基于Window管理器,直接在OSD Layer上画图的流程

dfb->CreateSurface( dfb, &desc, &primary ); >>>获取OSD Layerprimary Surface

primary->SetColor(primary,0x55,0x55,0x00,0xff);

primary->FillRectangle(primary,0,0,80,80);>>> 填充一个长宽都为80的矩形区域

IDirectFBSurface_FillRectangle>>>surface矩形填充接口

dfb_gfxcard_fillrectangles>>>抽象出来的显卡矩形填充接口

dfb_gfxcard_state_check>>>检测是否存在显卡的硬件加速渲染接口      card->funcs.FillRectangle>>>通过函数指针调用显卡驱动

gFillRectangle>>>如果不存在则使用软件渲染函数,即直接对显存进行内存拷贝操作

primary->Flip( primary, NULL, 0 );

 

dfb_surface_flip( data->surface, false );>>> 改变surface buffer index

dfb_surface_notify( surface, CSNF_FLIP );>>>

dfb_surface_dispatch( surface, ¬ification, dfb_surface_globals );>>> 通过fusion通知进行surface_listener flip操作

fusion_reactor_dispatch>> ioctl (FUSION_REACTOR_DISPATCH)把消息丢给内核模块。

 

IDirectFBSurface_Flip>>> surface_listener收到消息后调用

dfb_back_to_front_copy >>>显示缓冲区之间的交换

情况2:基于Window管理器的画矩形框流程

dfb->GetDisplayLayer( dfb, DLID_PRIMARY, &layer )>>>获取Layer对象

 layer->CreateWindow( layer, &desc, &window2 )>>>在创建Window对象,并将其加入Window Stack

window2->GetSurface( window2, &window_surface2 );>>>获取WindowSurface

window2->SetOpacity( window2, 0xFF );>>>设置Window为不透明

window2->CreateEventBuffer( window2, &buffer );>>>创建Window事件缓冲区

window_surface2->SetColor( window_surface2,0x00, 0x30, 0x10, 0xc0 );>>>设置Surface上画笔的颜色

window_surface2->DrawRectangle( window_surface2, 0, 0, desc.width, desc.height );>>>Window2上的Surface画出矩形框

window_surface2->Flip( window_surface2, NULL, 0 );>>>显示Surface2上的图像缓存

=============需要进一步补充

阅读(1205) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~