3. DirectFB 架构总览
DirectFB 的定位并不是一个“画点画线”的绘图库,而是一套面向嵌入式 Linux 的轻量级图形栈。它向下直接对接 framebuffer、显示控制器、输入设备与 GPU,向上提供窗口系统、图层合成、输入事件分发和硬件加速接口。理解 DirectFB 的关键,不是记住某个 API,而是看清它如何把“应用请求”逐层翻译成“硬件动作”。本节从整体架构出发,梳理核心模块、图形核心、输入核心、窗口核心、图层管理器、显示驱动与硬件抽象之间的职责边界与协作关系。
一、整体分层:从应用到硬件的纵向结构
DirectFB 的架构可以按纵向分为四层。最上层是应用与上层图形库,例如直接调用 DirectFB API 的程序,或基于 GTK、Qt 等封装的嵌入式 UI。第二层是 DirectFB 核心与各管理器,包括图形核心、输入核心、窗口核心、图层管理器和显示驱动接口。第三层是硬件抽象层,负责屏蔽不同 SoC 的显示控制器、输入控制器和加速器差异。最底层是 Linux 内核提供的 framebuffer、input 子系统、DRM 或厂商私有驱动。
这种分层带来的直接好处是:应用不需要知道当前屏幕是单图层还是多图层,也不需要关心输入事件来自触摸屏还是遥控器。应用只面对统一的 IDirectFB、ISurface、IWindow、IInputDevice 等接口,由核心把请求路由到正确的管理器和驱动。
二、核心模块与四大管理器的职责
核心模块是 DirectFB 的入口和总控。它负责初始化系统、解析配置文件、注册各类驱动、创建全局单例对象,并维护接口版本与能力协商。应用调用 DirectFBCreate() 后拿到的 IDirectFB,就是核心暴露给应用的总接口。
图形核心管理所有可绘制表面。它负责 Surface 的创建、锁定、解锁、Blit、填充、拉伸和格式转换。图形核心并不直接操作寄存器,而是根据当前 Surface 的像素格式和加速能力,选择软件路径或调用驱动提供的加速函数。
输入核心负责输入设备的枚举、打开和事件读取。它把来自 /dev/input/eventX 的原始事件转换为 DirectFB 的 DFBInputEvent,再根据窗口焦点和坐标位置分发给目标窗口。输入核心还处理键盘映射、鼠标加速和触摸坐标校准。
窗口核心在图形核心之上提供窗口语义。它管理窗口的创建、显示、隐藏、移动、层级和焦点。窗口核心决定哪个窗口接收输入,并在窗口重叠时通过裁剪区域限制绘制范围,避免无效绘制。
图层管理器面向显示控制器的多图层能力。它把窗口或 Surface 绑定到硬件图层,设置图层的位置、大小、Z 序、透明度和像素格式。当硬件图层数量不足时,图层管理器会退化为软件合成,把多个 Surface 混合到主图层。
三、显示驱动与硬件抽象层
显示驱动与硬件抽象层是 DirectFB 与具体 SoC 之间的“翻译层”。DirectFB 定义了一组驱动接口,包括 GraphicsDriverFuncs、InputDriverFuncs、SystemDriverFuncs 和 LayerDriverFuncs。芯片厂商或板级支持包只需实现这些接口,就能把自家显示控制器接入 DirectFB。
硬件抽象层进一步把“能力”抽象出来。例如,某块屏幕支持两个硬件图层、支持 ARGB 格式、支持硬件 Blit,但不支持旋转。DirectFB 在初始化时读取这些能力,运行时据此选择最优路径。如果硬件不支持某个操作,就回退到软件实现。这种“能力协商 + 软件回退”的机制,是 DirectFB 能适配大量嵌入式平台的关键。
| 模块 | 主要职责 | 典型接口/对象 | 向下依赖 |
|---|---|---|---|
| 核心模块 | 初始化、配置、驱动注册、全局资源管理 | IDirectFB | 各驱动接口 |
| 图形核心 | Surface 创建、Blit、填充、格式转换 | ISurface | gfxdriver |
| 输入核心 | 输入设备管理、事件读取与分发 | IInputDevice | inputdriver |
| 窗口核心 | 窗口生命周期、焦点、层级、裁剪 | IWindow | 图形核心、输入核心 |
| 图层管理器 | 硬件图层分配、Z 序、合成与回退 | ILayer | layerdriver、显示驱动 |
| 显示驱动/HAL | 屏蔽 SoC 差异,提供能力协商与加速 | DriverFuncs | Framebuffer、DRM、厂商驱动 |
四、典型场景:一次窗口绘制与输入响应
假设应用创建一个窗口,并在窗口中绘制一张图片,同时响应触摸点击。整个过程可以拆成两条链路。
绘制链路:应用调用 CreateSurface 创建 Surface,图形核心分配内存并设置像素格式;应用调用 Blit 把图片拷贝到 Surface;窗口核心把该 Surface 关联到窗口;图层管理器把窗口绑定到某个硬件图层;显示驱动把图层地址写入显示控制器寄存器;最终屏幕刷新。
输入链路:触摸屏产生中断,内核 input 子系统生成事件;输入核心从设备节点读取事件,转换为 DFBInputEvent;窗口核心根据坐标和焦点判断目标窗口;应用通过 WaitForEvent 或回调收到事件;应用更新界面,再次触发绘制链路。
/* 简化示意:创建窗口并等待输入事件 */
DFBWindowDescription desc;
desc.flags = DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT;
desc.posx = 100;
desc.posy = 80;
desc.width = 640;
desc.height = 480;
IDirectFBWindow *window;
dfb->CreateWindow(dfb, &desc, &window);
DFBWindowEvent event;
while (window->WaitForEvent(window, &event) == DFB_OK) {
if (event.type == DWET_BUTTONDOWN) {
/* 处理触摸按下,更新界面 */
}
}
五、常见误区与复盘
误区一:把 DirectFB 当成单纯的绘图库。实际上它包含窗口、输入、图层和驱动管理,是一个小型图形系统。只调用绘图 API 而不理解窗口与图层关系,容易出现“画了但看不见”的问题。
误区二:认为所有操作都会走硬件加速。DirectFB 会根据驱动能力选择路径。如果驱动没有实现某个 Blit 或格式转换,核心会回退到软件实现,性能会明显下降。排查性能问题时,应优先确认当前操作是否命中加速路径。
误区三:忽略图层数量限制。很多嵌入式显示控制器只支持 1 到 3 个硬件图层。当应用创建过多窗口或图层时,图层管理器会进行软件合成,带来额外 CPU 开销。设计 UI 时应尽量复用图层,减少不必要的叠加。
误区四:输入事件与窗口焦点脱节。输入核心只负责产生事件,窗口核心才决定事件归属。如果窗口没有获得焦点,或者坐标被其他窗口遮挡,应用就收不到预期事件。调试时应同时观察输入设备、窗口层级和焦点状态。
复盘来看,DirectFB 的架构价值在于“分层解耦”和“能力协商”。核心模块统一入口,四大管理器各司其职,显示驱动与硬件抽象层屏蔽平台差异。掌握这条纵向链路,后续学习 Surface 操作、窗口管理、图层配置和输入处理时,就能把每个 API 放回正确的位置,而不是孤立地记忆函数名。