3. DirectFB 架构总览

DirectFB 的定位并不是一个“画点画线”的绘图库,而是一套面向嵌入式 Linux 的轻量级图形栈。它向下直接对接 framebuffer、显示控制器、输入设备与 GPU,向上提供窗口系统、图层合成、输入事件分发和硬件加速接口。理解 DirectFB 的关键,不是记住某个 API,而是看清它如何把“应用请求”逐层翻译成“硬件动作”。本节从整体架构出发,梳理核心模块、图形核心、输入核心、窗口核心、图层管理器、显示驱动与硬件抽象之间的职责边界与协作关系。

核心结论:DirectFB 采用“核心 + 管理器 + 驱动”的分层结构。应用通过 IDirectFB 接口进入,核心负责资源与生命周期,图形/输入/窗口/图层管理器分别处理不同域,显示驱动与硬件抽象层最终把操作落到具体 SoC 的 framebuffer、图层寄存器和输入设备上。

一、整体分层:从应用到硬件的纵向结构

DirectFB 的架构可以按纵向分为四层。最上层是应用与上层图形库,例如直接调用 DirectFB API 的程序,或基于 GTK、Qt 等封装的嵌入式 UI。第二层是 DirectFB 核心与各管理器,包括图形核心、输入核心、窗口核心、图层管理器和显示驱动接口。第三层是硬件抽象层,负责屏蔽不同 SoC 的显示控制器、输入控制器和加速器差异。最底层是 Linux 内核提供的 framebuffer、input 子系统、DRM 或厂商私有驱动。

这种分层带来的直接好处是:应用不需要知道当前屏幕是单图层还是多图层,也不需要关心输入事件来自触摸屏还是遥控器。应用只面对统一的 IDirectFB、ISurface、IWindow、IInputDevice 等接口,由核心把请求路由到正确的管理器和驱动。

DirectFB 架构总览:应用 → 核心 → 管理器 → 驱动 → 硬件 应用 / 上层图形库 IDirectFB · ISurface · IWindow · IInputDevice · ILayer DirectFB 核心(Core) 资源管理 · 生命周期 · 接口注册 · 事件循环 · 配置解析 图形核心 Surface / Blit Draw / 加速 输入核心 InputDevice 事件分发 窗口核心 Window / Stack 焦点 / 裁剪 图层管理器 Layer / 合成 Z 序 / 显示 显示驱动 + 硬件抽象层(HAL) gfxdriver · inputdriver · systemdriver · layerdriver · 加速器封装 硬件:Framebuffer / 显示控制器 / 触摸屏 / 键盘 / GPU

二、核心模块与四大管理器的职责

核心模块是 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 放回正确的位置,而不是孤立地记忆函数名。