2. KMS核心概念:CRTC、Encoder、Connector、Plane、Framebuffer的角色与数据流
在DRM/KMS框架中,显示管道被抽象为五个核心对象:CRTC、Encoder、Connector、Plane和Framebuffer。理解这五个对象的角色及其数据流关系,是掌握atomic提交机制的基础。本章将逐一剖析每个对象的功能定位,并通过数据流图展示它们如何协同工作,将应用程序的像素数据最终呈现在物理显示器上。
2.1 五对象角色定义与职责
下表从功能定位、核心属性和典型操作三个维度,对比了五个KMS核心对象的差异:
| 对象 | 功能定位 | 核心属性 | 典型操作 |
|---|---|---|---|
| CRTC | 显示控制器,驱动时序生成 | 模式(mode)、扫描位置、背景色 | 设置显示模式、开启/关闭显示 |
| Plane | 图层合成单元,叠加多个Framebuffer | 源矩形、目标矩形、Z序、alpha | 关联Framebuffer、设置位置与大小 |
| Framebuffer | 内存中的像素数据缓冲区 | 宽度、高度、像素格式、dma-buf句柄 | 创建/销毁、映射、导出dma-buf |
| Encoder | 信号编码器,将CRTC输出转为物理信号 | 编码类型(HDMI/DP/LVDS)、可能克隆 | 绑定CRTC、设置编码参数 |
| Connector | 物理连接器,检测显示器状态 | 连接状态、EDID、物理类型 | 热插拔检测、读取EDID |
2.2 数据流全景:从Framebuffer到显示器
下图展示了KMS五对象之间的数据流关系。像素数据从用户空间应用程序开始,经过Framebuffer、Plane、CRTC、Encoder,最终通过Connector到达物理显示器:
2.3 各对象深度解析
2.3.1 Framebuffer:像素数据的载体
Framebuffer是KMS中最接近内存的对象。它不直接参与显示时序,而是作为像素数据的存储容器。每个Framebuffer对应一个或多个内存缓冲区(支持立体/多层缓冲),通过dma-buf机制与GPU或显示控制器共享物理内存。
// Framebuffer创建示例(用户空间)
struct drm_mode_fb_cmd2 fb_cmd = {
.width = 1920,
.height = 1080,
.pixel_format = DRM_FORMAT_XRGB8888,
.handles[0] = gem_handle, // GEM对象句柄
.pitches[0] = 1920 * 4, // 每行字节数
};
int ret = drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &fb_cmd);
// fb_cmd.fb_id 即为创建的Framebuffer ID
2.3.2 Plane:图层合成引擎
Plane是KMS中实现硬件图层叠加的核心。现代显示控制器通常支持多个硬件图层(主层、光标层、视频层等),每个Plane对应一个硬件图层。Plane负责从Framebuffer读取像素,进行缩放、裁剪、旋转等变换,然后按照Z序与其它Plane合成。
| Plane类型 | 典型用途 | 硬件特性 |
|---|---|---|
| Primary Plane | 主显示层,通常显示桌面背景 | 必须存在,支持全屏显示 |
| Cursor Plane | 鼠标光标层 | 尺寸小(通常64x64),更新快 |
| Overlay Plane | 视频播放、画中画 | 支持YUV格式、硬件缩放 |
2.3.3 CRTC:显示时序的指挥官
CRTC(Cathode Ray Tube Controller,历史名称沿用)是KMS管道的控制核心。它负责:
- 时序生成:根据设定的显示模式(如1920x1080@60Hz)生成行同步、场同步、消隐等时序信号。
- 扫描控制:决定从哪个Plane读取像素,以及读取的起始位置和扫描顺序。
- 背景处理:当所有Plane都不覆盖某个像素时,显示CRTC设置的背景色。
// CRTC模式设置示例(用户空间)
drmModeCrtcPtr crtc = drmModeGetCrtc(fd, crtc_id);
drmModeSetCrtc(fd, crtc_id, fb_id, x, y, connectors, connector_count, mode);
// 该调用会同时设置CRTC的模式、关联Framebuffer和Connector
2.3.4 Encoder:信号编码的桥梁
Encoder将CRTC输出的并行像素数据转换为特定接口标准的串行信号。常见的Encoder类型包括:
- TMDS Encoder:用于HDMI/DVI接口,将RGB数据编码为TMDS差分信号。
- LVDS Encoder:用于嵌入式显示屏,将并行数据转换为低压差分信号。
- DisplayPort Encoder:将数据打包为DP微包,支持更高带宽和辅助通道。
2.3.5 Connector:物理世界的接口
Connector是KMS中唯一与物理世界直接交互的对象。它的核心职责包括:
- 连接检测:通过硬件引脚或辅助通道检测显示器是否连接。
- EDID读取:通过I2C或DP辅助通道读取显示器的EDID数据,获取支持的分辨率列表。
- 物理类型标识:标识连接器类型(HDMI、DP、eDP、VGA等),驱动据此选择合适的Encoder。
2.4 对象间的绑定关系
KMS五对象之间存在严格的绑定约束,这些约束在atomic提交中必须满足:
2.5 atomic提交中的数据流整合
在atomic提交模式下,上述五个对象的状态更新被封装为一个原子事务。以下是一个典型的atomic提交数据流步骤:
- 创建Framebuffer:用户空间分配GEM缓冲区,通过
DRM_IOCTL_MODE_ADDFB2创建Framebuffer对象。 - 准备Plane状态:设置Plane关联的Framebuffer ID、源矩形(裁剪区域)、目标矩形(显示位置)和Z序。
- 准备CRTC状态:设置显示模式(分辨率、刷新率)、背景色,以及是否启用显示。
- 准备Encoder/Connector状态:设置Encoder的编码参数,确认Connector的连接状态。
- 提交atomic commit:将所有对象的状态打包为drm_atomic_state,通过
DRM_IOCTL_MODE_ATOMIC一次性提交。 - 硬件生效:驱动在下一个vblank时刻原子性地切换所有硬件寄存器,完成显示更新。
// atomic提交核心代码片段(用户空间)
struct drm_mode_atomic atomic = {0};
// 准备对象属性
atomic.flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
atomic.count_objs = 3; // CRTC + Plane + Connector
atomic.objs_ptr = (uint64_t)obj_ids;
atomic.count_props_ptr = (uint64_t)count_props;
atomic.props_ptr = (uint64_t)prop_ids;
atomic.values_ptr = (uint64_t)prop_values;
int ret = drmIoctl(fd, DRM_IOCTL_MODE_ATOMIC, &atomic);
2.6 本章小结
KMS五对象构成了Linux显示子系统的核心抽象层:
- Framebuffer是像素数据的物理载体,通过dma-buf实现零拷贝共享。
- Plane是硬件图层合成单元,支持缩放、裁剪和alpha混合。
- CRTC是显示时序的生成器,控制整个管道的扫描节奏。
- Encoder将并行像素信号编码为接口标准信号。
- Connector是物理世界的接口,负责连接检测和EDID读取。