DirectFB 代码导读

    技术2022-05-19  21

    DirectFB 代码导读

     

    转载时请注明出处和作者联系方式 作者联系方式:李先静 <xianjimli at hotmail dot com>

     

    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 只有一个模糊的概念,抱歉不能在这些方面提供更多信息。我对图形算法不太熟悉,大家可以问我某个流程是怎么走的,某个对象与另外一个对象是怎么交互的,但不要问我某个算法是怎么实现的。

     

    欢迎交流。


    最新回复(0)