DRM 显示子系统:Atomic 模式设置
1. 显示状态不能逐项直接写入的原因
显示配置通常不是一个寄存器的事,而是一组对象状态一起变化:
- plane 换了 framebuffer;
- plane 的显示位置变了;
- crtc 可能开了或关了;
- connector 可能切了一个新模式;
- bridge 链路也可能要跟着重配。
如果驱动见到一项就写一项,中间态就会暴露出来。最典型的后果有三个:
- 画面撕裂;
- 半帧黑屏;
- 提交到一半才发现某个条件不满足,硬件已经改乱了。
Atomic 的思路很克制:
先在软件里构造一份完整新状态,确认它可行,再一次性切过去。
2. Atomic state
Atomic 提交里最关键的不是某个单一结构体,而是“每个对象都有一份待提交的新状态”。
直观上可以把它理解成:
- plane 有 plane state;
- crtc 有 crtc state;
- connector 有 connector state;
- 一次提交把这些 state 收拢到同一个 atomic transaction 里。
也就是说,Atomic 真正解决的是“多对象联动更新”的问题,而不是单纯给某个 ioctl 改了个名字。
3. 两阶段:先 check,再 commit
Atomic 提交分成两个阶段:
第一阶段:check
只验证,不碰硬件。
常见检查项包括:
- plane 格式是否支持;
- 缩放比例是否超限;
- 这个 plane 能不能挂到这个 CRTC;
- 带宽是否足够;
- 模式是否超出某个输出链路上限。
第二阶段:commit
只有 check 全部通过,才进入真正提交。提交时再去准备 buffer、交换状态、写寄存器、安排 vblank event 和链路上下电。
4. 一次 Atomic Commit 的大致调用链
把细节先压住,只看主干,一次提交通常可以理解成下面这条路:
sequenceDiagram
participant U as Userspace
participant IO as DRM ioctl
participant ST as Atomic State
participant CK as atomic_check
participant CM as atomic_commit
participant HW as Hardware
U->>IO: drmModeAtomicCommit()
IO->>ST: 创建并填充新状态
ST->>CK: 校验整组状态
CK-->>IO: 通过 / 失败
IO->>CM: 进入提交阶段
CM->>HW: 更新 plane / crtc / bridge / panel 相关硬件状态
HW-->>U: 通过 event 在合适时机通知完成
真正进到提交阶段后,helper 层通常还会再做几步拆分,比如:
- prepare 阶段:准备 framebuffer 或 fence;
- swap state:把新状态挂成当前状态;
- modeset disable / enable:处理链路开关;
- plane update:更新图层输入;
- crtc flush:在合适时机把这一组改动真正推向硬件。
这里需要注意一点,不是“plane 更新完就自己 flush 了”,实际更常见的做法是:
plane 各自更新,最后由 CRTC 统一 flush。
5. atomic_check
atomic_check 的真正价值,是把那些只有结合整次提交上下文才能判断的约束挡在硬件提交前面。
举几个典型场景:
- 同一个 plane 不能同时路由到两个 CRTC;
- 同一个 CRTC 上多个 plane 叠起来后超了带宽;
- 缩放引擎只能支持有限倍率;
- 某条输出链路下只能接受特定总线格式;
- 模式虽然本身合法,但和当前路由组合起来不合法。
这些事情单看某一个对象都不完整,只有站在整次提交的视角里才看得清。

浙公网安备 33010602011771号