本文转自李先静先生的blog:http://blog.csdn.net/absurd/article/details/1001641
DirectFB是一个庞大的系统,对它进行彻底分析要花不少时间。幸好多数情况下,只要弄清楚它的基本架构,再重点读一些关键的代码,也就差不多了。前几个月为了完善DFB的窗口管理器,我花了一些时间去研究DFB的架构。把其中一些经验写到这里,供有兴趣的朋友参考。
总的说来,DFB由以下几部分组成:
1. 基本库函数。这部分代码在lib目录下,它分为三个部分:
- direct: 里面是一些公共函数,其中包括哈希表、链表、线程、调试信息、signal处理、优化过的memcpy和平台相关的一些函数。
- fusion:它有两个版本,一个是针对单进程的,要求所有应用程序在一个进程中运行,这相对来说比较简单。另外一个是针对多进程的,应用程序可以在多个进程中运行。它实现了一些进程间通信机制,其中包括互斥、共享内存、共享内存中的vector实现、带引用计数的内核对象和reactor等。多进程版本还需要一个内核模块linux-fusion的支持。
- voodoo: 不清楚(若那位高手知道,请补充一下,谢谢)。
2. 对第三方组件库的包装。这部分代码在interfaces目录下。Interfaces可能会引起别人的误解,因为它并不是DFB对外提供的接口,而是把第三方组件纳入DFB的接口。它包括三类:
- 字体。字体有点阵字体和矢量字体之分,矢量字体又有诸如truetype之类几种格式。前者可能比较简单,而后者的处理相当复杂,要借助如freetype等第三方程序库来实现。DFB定义了IDirectFBFont接口来处理字体,在第三方字体程序库上加上一个adapter就可以在DFB中使用了。
- 图片。图片格式的种类很多,像BMP之类的位图处理可能比较简单,而像JPG和PNG等的图片,采用了高级的压缩技术,解压算法比较复杂,通常需要第三方程序库的支持。DFB定义了IDirectFBImageProvider接口来处理图片,在第三方图片程序库上加上一个adapter就可以在DFB中使用了。
- 视频。视频格式更多,解压算法也更复杂,自然也要借助第三方库来实现。DFB定义了IDirectFBVideoProvider接口来处理视频,在第三方视频程序库上加上一个adapter就可以在DFB中使用了。
3. 核心代码。这部分代码在src目录下。它可以分为两大类:
- 核心组件。DFB的core由多个部分组成,每个部分称为一个core_part,都实现同一个接口CorePart。这个接口并不描述它们的功能,而是用于管理的。初看这些函数时,可能会感到有些奇怪。最好要先了解DFB采用的master/slave模型:第一个运行应用程序是master进程,后来运行的应用程序是slave进程。master进程负责初始化和~初始化arena,它只能在所有slave退出之后才能退出。而slave进程则可以随时加入arena,也可以随时退出arena。
- CoreInitialize: master进程初始化arena。
- CoreJoin: slave进程进入arena时的初始化。
- CoreShutdown: master进程~初始化arena。
- CoreLeave:slave进程离开arena时的~初始化。
- CoreSuspend:休眠,主要用于省电功能。
- CoreResume:唤醒,主要用于省电功能。
核心组件包括下面几个组件:
- dfb_core_clipboard: 剪切板。
- dfb_core_colorhash:调色板。
- dfb_core_gfxcard:图形卡,主要完成基本的绘图功能,如绘直线、填充等等。
- dfb_core_input:输入设备。
- dfb_core_layers:分层功能,好像要硬件支持,通常都只有一个层。
- dfb_core_screens:逻辑屏幕(可能像X一样支持多个屏幕吧,不太清楚,有时间再研究)。
- dfb_core_system:显示输出,把gfxcard绘制后的图形数据输出到屏幕上,即可以通过fbdev输出到本机屏幕上,也可以通过sdl/x11/vnc输出到远程主机的屏幕上。对于像sdl/x11等,也包括对输入事件的处理。
- dfb_core_wm:窗口管理器。
以上这些core_part,有的是直接实现的,比如clipboard。有的只是一层包装,具体的实现在一个独立的共享库中,在运行时通过参数来控制加载具体的实现,如system。
- 对外接口。这主要是给上层应用程序使用的。其中包括:
- IDirectFBInputDevice: 输入设备
- IDirectFBScreen: 屏幕。
- IDirectFBSurface: 绘图表面。
- IDirectFBPalette: 调色板。
- IDirectFBFont: 字体
- IDirectFBImageProvider:图片
- IDirectFBVideoProvider:视频
- IDirectFBWindow:窗口
- DirectFBEventBuffer: 事件缓冲
4. 窗口管理器。这部分代码在wm目录下。DFB实现了两个窗口管理器。
- default:实现了基本的窗口管理功能,支持一些快捷键。
- unique:功能也很弱,不过架构还可以,加入自己的功能很方便。
5. 输入设备。这部分代码在inputdrivers目录下。其实这些代码并不是真正的驱动,只是一个adapter层,它把从linux设备文件读到的事件,转换成DFB自己的事件格式,然后调用dfb_input_dispatch把事件分发出去。
6. 输出设备。这部分代码在system目录下。这也是一个adapter层,主要对显示设备的抽象,有的也包括对输入事件的处理。其中包括:
- fbdev: 输出到frame buffer。
- osx: 输出到mac os上。
- vnc:输出到Virtual Network Computing(类似于微软远程桌面的一个协议)。
- x11:输出到X Window上,在0.9.24仍然有问题,建议使用SDL。
- sdl: 输出到Simple DirectMedia Layer。
7. 值得注意的几个问题:
- master/slave模型。master/slave是DFB的基本模型,一定要先了解它,否则很难了解DFB的基本架构。
- reactor模式。DFB中的消息,无论是进程内的,还是进程间的,都是通过reactor来传递的。这是一种简单的发布-订阅机制,谁关心谁就注册。不先弄清楚reactor的机制,很容易就被消息的流向搞糊涂了。
- 加锁术语。加锁/解锁动作常用lock/unlook、acquire/release、 wait/release等术语,而DFB里使用skirmish_prevail/skirmish_dismiss。
- 引用计数术语。增加/减少引用计数常用ref/unref、addref/release等术语。DFB里使用了ref/unref,同时增加了几个动作:link/unlink用于增加和减少全局引用计数,ref增加的计数,只要应用程序退出,fusion自动释放这个引用计数。而link增加的引用计数非要用unlink减少才行,应用程序退出时不会自动减少。inherit: 继承另外一个对象的引用计数,即把被继承的对象的引用计数加到继承者身来,不但如此,当被继承的对象的引用计数增减时,自动增减继承者的引用计数。
- 注册/注销术语。注册/注销常用register/unregister等术语,DFB使用了attach/detatch。
- 内核对象的宏。DFB用宏FUSION_OBJECT_METHODS去实现一个fusion object的子类,FUSION_OBJECT_METHODS是在object.h里定义的。像CoreWindow和CoreSurface等内核对象,都调用这个宏去实现自己的方法。
- CorePart的宏。DFB用宏DFB_CORE_PART去实现一个core part,DFB_CORE_PART是在core_parts.h定义的。
- 动态模块的加载。DFB并不要求动态加载模块实现特定的接口函数,而当模块被加载时(dlopen时),把自己安装到框架中。模块使用了gcc的__attribute__((constructor))扩展,模块被加载时,该函数自动执行,然后调用direct_modules_register注册自己。
- cardstate:我开始被blit函数弄糊涂了,并不像WIN32下那样要求指明源和目标。后来才知道它是调用另外的函数去设置源和目标,而不是通过参数来指定。
在研究DFB时,我的主要精力放在DFB的架构、窗口管理器、输入设备驱动和fusion上,其它地方花的时间比较少,特别是对gfx只有一个模糊的概念,抱歉不能在这些方面提供更多信息。我对图形算法不太熟悉,大家可以问我某个流程是怎么走的,某个对象与另外一个对象是怎么交互的,但不要问我某个算法是怎么实现的。
欢迎交流。