DRM Property 与 Atomic Commit 机制深度分析

2026-03-22

一、为什么需要 Property?

DRM (Direct Rendering Manager) 中的 Property 系统是用户空间配置显示硬件的核心机制。在传统 legacy 模式中,应用程序直接操作具体的硬件寄存器或结构体,但这种做法存在诸多问题:

  1. 硬件抽象:不同厂商的 GPU/IP 有不同的寄存器接口
  2. 原子操作:所有配置变更必须全部成功全部失败,避免中间状态导致显示异常
  3. 统一接口:无论是 Intel/AMD/ARM GPU,都可以通过统一的 property 接口进行配置

Property 的本质:将硬件参数抽象为键值对,用户空间只关心语义(如 “rotation”),而不关心底层如何实现。

// 每个 DRM 对象 (CRTC/Plane/Connector) 都有一个属性列表
struct drm_object_properties {
    int count;
    struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY];
    uint64_t values[DRM_OBJECT_MAX_PROPERTY];
};

二、Property 类型详解

2.1 RANGE 属性

用于无符号整数范围,内核会验证用户空间设置的值是否在范围内。

// 创建 RANGE 属性
struct drm_property *drm_property_create_range(
    struct drm_device *dev,
    u32 flags, 
    const char *name,
    uint64_t min, 
    uint64_t max);

// 实际示例:SRC_X, SRC_Y, SRC_W, SRC_H
prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
            "SRC_X", 0, UINT_MAX);
dev->mode_config.prop_src_x = prop;

2.2 ENUM 属性

用于枚举值,每个值有一个符号名称。

// 枚举值定义
struct drm_prop_enum_list {
    int type;
    const char *name;
};

// DPMS 示例
static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
    { DRM_MODE_DPMS_ON, "On" },
    { DRM_MODE_DPMS_STANDBY, "Standby" },
    { DRM_MODE_DPMS_SUSPEND, "Suspend" },
    { DRM_MODE_DPMS_OFF, "Off" },
};

// 创建 ENUM 属性
prop = drm_property_create_enum(dev, 0,
            "DPMS", drm_dpms_enum_list,
            ARRAY_SIZE(drm_dpms_enum_list));

2.3 BITMASK 属性

用于位掩码,允许同时设置多个值(0-63 位)。

// 旋转属性示例
static const struct drm_prop_enum_list rotation_enum[] = {
    { DRM_MODE_ROTATE_0, "rotate-0" },
    { DRM_MODE_ROTATE_90, "rotate-90" },
    { DRM_MODE_ROTATE_180, "rotate-180" },
    { DRM_MODE_ROTATE_270, "rotate-270" },
    { DRM_MODE_REFLECT_X, "reflect-x" },
    { DRM_MODE_REFLECT_Y, "reflect-y" },
};

prop = drm_property_create_bitmask(dev, 0, "rotation",
            rotation_enum, ARRAY_SIZE(rotation_enum));

2.4 BLOB 属性

用于存储二进制数据,如 EDID、MODE 信息、HDR 元数据等。

// 创建 BLOB 属性
struct drm_property_blob *drm_property_create_blob(
    struct drm_device *dev,
    size_t length,
    const void *data);

// 常见用途:MODE_ID (显示模式)
blob = drm_property_create_blob(dev, sizeof(mode), &mode);
connector->mode_blob = blob;

三、Property 创建与绑定

完整的 property 实现流程:

// 1. 驱动初始化阶段创建 property
static int my_driver_init(struct drm_device *dev) {
    struct drm_property *prop;
    
    // 创建各种 property
    prop = drm_property_create_range(dev, 0, "brightness", 0, 100);
    if (!prop) return -ENOMEM;
    priv->brightness_prop = prop;
    
    prop = drm_property_create_enum(dev, 0, "colormap",
            colormap_enum, ARRAY_SIZE(colormap_enum));
    if (!prop) return -ENOMEM;
    priv->colormap_prop = prop;
    
    return 0;
}

// 2. 绑定到具体的 DRM 对象
static int my_driver_bind(struct drm_device *dev) {
    // 绑定到 Plane
    drm_object_attach_property(&plane->base, 
        priv->rotation_prop, DRM_MODE_ROTATE_0);
    drm_object_attach_property(&plane->base,
        priv->alpha_prop, 255);
    
    // 绑定到 CRTC
    drm_object_attach_property(&crtc->base,
        dev->mode_config.prop_active, 1);
        
    // 绑定到 Connector
    drm_object_attach_property(&connector->base,
        dev->mode_config.dpms_property, DRM_MODE_DPMS_ON);
}

标准 Property 速查表

对象 标准 Property
CRTC ACTIVE, MODE_ID, VRR_ENABLED, GAMMA_LUT, DEGAMMA_LUT, CTM
Plane FB_ID, CRTC_ID, SRC_X/Y/W/H, CRTC_X/Y/W/H, rotation, alpha, color_encoding
Connector EDID, DPMS, link-status, scaling_mode, content_protection, max_bpc

四、Atomic Commit 机制

4.1 核心 API

// 1. 仅检查配置合法性,不提交
int drm_atomic_check_only(struct drm_atomic_state *state);

// 2. 阻塞式原子提交
int drm_atomic_commit(struct drm_atomic_state *state);

// 3. 非阻塞式原子提交
int drm_atomic_nonblocking_commit(struct drm_atomic_state *state);

4.2 状态结构体

Atomic 将整体状态拆分为每个对象独立的状态结构

drm_atomic_state
    ├── drm_crtc_state     (每个 CRTC 的状态)
    ├── drm_plane_state   (每个 Plane 的状态)
    └── drm_connector_state (每个 Connector 的状态)

驱动可以通过 drm_private_state 扩展这些结构:

// 驱动私有状态扩展示例
struct my_crtc_private_state {
    struct drm_private_state obj;
    u32 hw_config_reg;
    bool pipeline_enabled;
};

struct my_crtc_state {
    struct drm_crtc_state base;  // 必须内嵌
    struct my_crtc_private_state private;
};

4.3 Check vs Commit 流程

Userspace (Wayland Compositor/Mutter)
    │
    ▼ 创建 drm_atomic_state 并填充配置
drm_atomic_check_only()
    │
    ▼ 调用驱动 atomic_check() 回调
驱动 atomic_check():
    ├── 检查模式是否有效
    ├── 验证硬件能力
    ├── 计算带宽需求
    └── 返回 0 表示合法,-EINVAL 表示非法
    │
    ▼ 如返回错误,用户空间收到错误,终止
    │
drm_atomic_commit()
    │
    ▼ 调用驱动 atomic_commit() 回调
驱动 atomic_commit():
    ├── 禁用受影响的 CRTC/Plane
    ├── 配置新的显示模式
    ├── 启用新的 Plane 配置
    └── 触发 VBlank 等待
    │
    ▼ VBlank 到达后切换缓冲区
flip_done 事件 → 释放旧 framebuffer

4.4 Non-blocking Commit 与 Fence

非阻塞提交是现代显示系统的核心,支持多个应用同时提交而不阻塞渲染进程。

// 非阻塞提交流程
int my_atomic_commit(struct drm_device *dev,
                     struct drm_atomic_state *state,
                     bool nonblock) {
    int ret;
    
    if (nonblock) {
        // 1. 初始化 commit 跟踪
        ret = drm_atomic_helper_setup_commit(state, DRM_MODE_PAGE_FLIP_ASYNC);
        if (ret) return ret;
        
        // 2. 提交到硬件(不等待 VBlank)
        ret = my_hw_commit(state);
        if (ret) return ret;
        
        // 3. 完成后通过 fence 通知
        return 0;
    }
    
    // 阻塞模式
    drm_atomic_helper_commit_modeset_disables(dev, state);
    drm_atomic_helper_commit_modesets(dev, state);
    drm_atomic_helper_commit_planes(dev, state, 0);
    drm_atomic_helper_wait_for_vblanks(dev, state);
}

关键辅助函数

函数 用途
drm_atomic_helper_wait_for_fences() 等待所有 fence 信号
drm_atomic_helper_wait_for_vblanks() 等待所有 CRTC 的 VBlank
drm_atomic_helper_wait_for_flip_done() 等待页面翻转完成

4.5 Page Flip 在 Atomic 模式

// 页面翻转 (atomic 方式)
drm_atomic_commit() {
    // 在 plane_state 中指定新的 FB
    plane_state->fb = new_fb;
    plane_state->crtc = crtc;
    plane_state->crtc_x = 0;
    plane_state->crtc_y = 0;
    plane_state->crtc_w = mode->hdisplay;
    plane_state->crtc_h = mode->vdisplay;
    plane_state->src_x = 0;
    plane_state->src_y = 0;
    plane_state->src_w = mode->hdisplay << 16;
    plane_state->src_h = mode->vdisplay << 16;
    
    // 内核自动在下一个 VBlank 切换缓冲区
}

// flip 事件结构
struct drm_crtc_commit {
    struct drm_crtc *crtc;
    struct completion hw_done;      // 硬件操作完成
    struct completion flip_done;    // 页面翻转完成
    struct dma_fence *fence;       // 同步 fence
};

五、典型驱动实现框架

static const struct drm_mode_config_funcs my_mode_config_funcs = {
    .fb_create = my_fb_create,
    .atomic_check = my_atomic_check,
    .atomic_commit = my_atomic_commit,
};

// atomic_check 实现
static int my_atomic_check(struct drm_device *dev, 
                           struct drm_atomic_state *state) {
    int ret;
    
    // 1. 调用 helper 检查基础配置
    ret = drm_atomic_helper_check(dev, state);
    if (ret) return ret;
    
    // 2. 驱动特定检查
    for_each_new_crtc_in_state(state, crtc, old_crtc, i) {
        struct drm_crtc_state *crtc_state = state->crtcs[i].new_state;
        
        // 检查模式是否支持
        if (!my_crtc_mode_valid(crtc_state->mode))
            return -EINVAL;
            
        // 检查带宽
        if (my_bandwidth_exceeds(crtc_state))
            return -ENOSPC;
    }
    
    return 0;
}

// atomic_commit 实现
static int my_atomic_commit(struct drm_device *dev,
                            struct drm_atomic_state *state,
                            bool nonblock) {
    // 使用 helper 函数
    if (nonblock) {
        return drm_atomic_helper_commit(dev, state, true);
    }
    
    drm_atomic_helper_commit_modeset_disables(dev, state);
    drm_atomic_helper_commit_modesets(dev, state);
    drm_atomic_helper_commit_planes(dev, state, 0);
    drm_atomic_helper_wait_for_vblanks(dev, state);
    
    return 0;
}

六、总结

概念 核心要点
Property 用户空间配置硬件的抽象接口,支持 RANGE/ENUM/BITMASK/BLOB 等类型
Atomic Commit 所有配置变更原子性应用,避免中间状态
Check vs Commit Check 验证合法性,Commit 提交到硬件
Non-blocking 通过 fence 机制实现异步提交,提高并发性能
Page Flip 在 VBlank 时切换缓冲区,通过 flip_done 事件通知

参考资料

  • Linux Kernel DRM 文档: https://www.kernel.org/doc/html/latest/gpu/drm-kms.html
  • Property 头文件: include/drm/drm_property.h
  • Atomic 核心: drivers/gpu/drm/drm_atomic.c
  • Atomic Helper: drivers/gpu/drm/drm_atomic_helper.c

感谢阅读!