一、简介
在 Linux DRM(Direct Rendering Manager)子系统中,Plane(平面)代表了一个图像源,可以在扫描输出过程中与 CRTC 混合或叠加显示。每个 Plane 从 drm_framebuffer
中获取输入数据,并负责图像的裁剪、缩放、旋转等变换,最终显示在 CRTC 代表的显示区域上。
Plane 分为三种类型:
Primary Plane:主平面,通常用于显示主内容,每个 CRTC 必须有一个主平面。
Cursor Plane:光标平面,用于显示硬件光标。
Overlay Plane:覆盖平面,用于额外的叠加层(如视频播放)。
二、代码分析
1. drm_plane.c
这是 DRM 核心中 Plane 的主要实现文件,包含了 Plane 的创建、初始化、销毁、属性管理等核心功能。
主要函数及作用:
函数名 | 作用 |
---|---|
drm_universal_plane_init | 初始化一个通用 Plane 对象 |
__drm_universal_plane_init | 内部函数,实际执行 Plane 初始化 |
drmm_universal_plane_alloc | 分配并初始化一个受 DRM 管理的 Plane |
drm_plane_cleanup | 清理 Plane 资源,不释放结构体本身 |
drm_plane_force_disable | 强制禁用 Plane(非原子模式) |
drm_mode_setplane | 处理 DRM_IOCTL_MODE_SETPLANE ioctl |
drm_mode_cursor_ioctl | 处理光标设置 ioctl |
drm_mode_page_flip_ioctl | 处理页面翻转 ioctl |
drm_plane_enable_fb_damage_clips | 启用 Framebuffer 损伤区域属性 |
drm_plane_create_scaling_filter_property | 创建缩放滤波器属性 |
2. drm_plane_helper.c
这个文件提供了一些过渡性的辅助函数,主要用于传统(非原子)模式下的 Plane 操作,帮助驱动逐步迁移到原子模式。
主要函数及作用:
函数名 | 作用 |
---|---|
drm_primary_helper_update | 用于主 Plane 的更新操作(传统模式) |
drm_primary_helper_disable | 用于主 Plane 的禁用操作(传统模式) |
drm_primary_helper_destroy | 用于主 Plane 的销毁操作 |
drm_plane_helper_check_update | 检查 Plane 更新参数是否有效 |
drm_universal_plane_init()-> __drm_universal_plane_init()-> drm_mode_object_add()-> create_in_format_blob()-> drm_object_attach_property() [多次]drm_mode_setplane()-> drm_plane_find()-> drm_framebuffer_lookup()-> setplane_internal()-> __setplane_internal() 或 __setplane_atomic()drm_mode_cursor_ioctl()-> drm_mode_cursor_common()-> drm_mode_cursor_universal()-> __setplane_internal() 或 __setplane_atomic()drm_mode_page_flip_ioctl()-> drm_crtc_find()-> drm_framebuffer_lookup()-> crtc->funcs->page_flip() 或 crtc->funcs->page_flip_target()drm_primary_helper_update()-> drm_plane_helper_check_update()-> crtc->funcs->set_config()drm_primary_helper_disable()-> 返回 -EINVAL(表示需驱动自己实现)drm_primary_helper_destroy()-> drm_plane_cleanup()-> kfree(plane)
drm_plane.c
是 Plane 的核心实现,包含生命周期管理、属性控制、IOCTL 处理等。drm_plane_helper.c
提供传统模式下的辅助函数,主要用于过渡期。现代 DRM 驱动应优先使用原子模式,逐步弃用传统辅助函数。
Plane 的类型、格式、修饰符、损伤区域、缩放滤波等属性都由这些函数管理。
drm_plane_helper.c 和 drm_plane.c 代码分析
这两个文件是 Linux 内核 DRM (Direct Rendering Manager) 子系统中与平面 (Plane) 管理相关的核心组件。平面是 DRM KMS (Kernel Mode Setting) 框架中的关键抽象,用于表示图像源,可以在扫描输出过程中与 CRTC (Cathode Ray Tube Controller) 混合或叠加。它们与 GPU 的显示硬件密切相关,支持裁剪、缩放、旋转和 Z 位置等属性。
- drm_plane_helper.c:这是一个辅助库文件,提供主平面 (Primary Plane) 的实现支持,以及从遗留接口向原子 (Atomic) 接口的过渡函数。文件强调驱动应逐步迁移到原子接口,而这些辅助函数是过渡性的。它处理主平面的更新、禁用和销毁,并与 CRTC 和连接器交互。版权从 2014 年 Intel 开始,主要用于简化驱动开发,但注释警告新驱动不应依赖这些过渡性辅助。
- drm_plane.c:这是平面管理的核心文件,实现平面的初始化、属性管理、损伤跟踪 (Damage Tracking) 和用户空间接口 (如 ioctl)。它定义了平面的类型 (主平面、覆盖平面、游标平面),支持修改器 (Modifiers) 和原子模式设置。文件处理平面与帧缓冲区 (Framebuffer) 的关联、标准属性 (如 IN_FORMATS、type) 和遗留 ioctl(如光标和页面翻转)。版权从 2016 年 Intel 开始,强调驱动必须为所有平面设置修改器支持。
这些文件紧密协作:drm_plane_helper.c 依赖 drm_plane.c 中的平面结构和函数(如 drm_plane_cleanup),而 drm_plane.c 提供更底层的平面管理。它们与 GPU 相关,因为平面操作直接映射到 GPU 的硬件平面(如 Intel 的 Universal Planes 或 AMD 的 Overlay),涉及缓冲区格式、修改器和原子更新。
关键函数分析
以下列出两个文件中需要注意和熟悉的关键函数。这些函数是导出的(EXPORT_SYMBOL),常用于驱动实现钩子、初始化或用户空间交互。重点关注:
- 初始化和清理函数:用于设置平面对象。
- 更新和检查函数:处理平面状态变化,与原子模式设置相关。
- 属性管理函数:暴露给用户空间的属性,如损伤剪辑或缩放过滤。
- ioctl 和遗留支持:处理用户空间请求,如光标移动或页面翻转。
- 辅助迭代器:用于损伤处理。
我使用表格分类,便于阅读。每个函数包括描述、为什么重要(注意点)和在哪个文件定义。
函数名 | 文件 | 描述 | 为什么需要注意和熟悉 |
---|---|---|---|
drm_plane_helper_check_update | drm_plane_helper.c | 检查平面更新的有效性,包括源/目标矩形、旋转、缩放和可见性,使用 drm_atomic_helper_check_plane_state。 | 这是更新平面前的关键验证函数,确保硬件约束(如缩放范围、位置)。在过渡性驱动中常用,错误可能导致显示异常。熟悉它能帮助调试原子状态检查。 |
drm_primary_helper_update | drm_plane_helper.c | 更新主平面,包括设置模式、连接器和帧缓冲区。调用 CRTC 的 set_config 并处理可见性。 | 主平面是 CRTC 启用必需的,此函数桥接遗留 set_config 接口。注意它不调用 drm_mode_set_config_internal,以避免额外引用计数。迁移到原子接口时需替换。 |
drm_primary_helper_disable | drm_plane_helper.c | 禁用主平面,返回 -EINVAL(因为主平面通常不可禁用)。 | 简单但重要:防止用户空间禁用主平面,导致 CRTC 失效。熟悉以理解遗留接口的限制。 |
drm_primary_helper_destroy | drm_plane_helper.c | 销毁主平面,调用 drm_plane_cleanup 并释放内存。 | CRTC 销毁时调用,确保平面正确清理。导出函数,驱动常用作销毁钩子。注意内存管理(kfree)。 |
drm_primary_helper_funcs | drm_plane_helper.c | 主平面的函数表,包括 update、disable 和 destroy 钩子。 | 这是主平面的标准回调表。驱动通过此表注册钩子。熟悉以实现自定义主平面行为。 |
drm_universal_plane_init | drm_plane.c | 初始化通用平面对象,包括分配格式、修改器、属性附件(如 type、IN_FORMATS)。 | 核心初始化函数,所有平面创建必须调用。注意修改器支持(必须设置,即使仅线性)和类型(Primary/Overlay/Cursor)。导出,驱动广泛使用;警告:使用 drmm_ 版本以支持管理资源。 |
__drm_universal_plane_init | drm_plane.c | drm_universal_plane_init 的内部变体,支持 va_list 命名。 | 内部实现,处理平面名称格式化。熟悉以理解初始化细节,如格式计数限制(<=64)。 |
drm_plane_enable_fb_damage_clips | drm_plane.c | 启用 FB_DAMAGE_CLIPS 属性,允许用户空间指定损伤矩形。 | 损伤跟踪的关键函数,提高虚拟设备效率(如网络传输)。注意:必须显式启用,否则属性不可用。导出,用于优化驱动。 |
drm_plane_get_damage_clips_count | drm_plane.c | 返回 FB_DAMAGE_CLIPS 中的矩形数量。 | 简单计数器,但重要于处理用户空间损伤提示。熟悉以迭代损伤区域,避免全平面更新。 |
drm_plane_get_damage_clips | drm_plane.c | 返回 FB_DAMAGE_CLIPS 中的 &drm_mode_rect 数组。 | 获取用户空间损伤矩形。注意坐标是非固定点的(不像 src),且驱动可读取更多区域。导出,与 drm_atomic_helper_damage_iter_* 协作使用。 |
drm_plane_create_scaling_filter_property | drm_plane.c | 创建 SCALING_FILTER 属性,支持默认/最近邻过滤。 | 暴露缩放过滤给用户空间。注意支持掩码(必须包括 DEFAULT)。导出,用于高级缩放硬件的驱动。 |
drm_mode_cursor_ioctl | drm_plane.c | 处理遗留光标 ioctl,包括设置/移动光标。 | 用户空间光标控制入口。处理遗留和原子模式,支持热区。注意与 drm_mode_cursor2_ioctl 的兼容。 |
drm_mode_cursor2_ioctl | drm_plane.c | 扩展光标 ioctl,支持热区 (hot_x/hot_y)。 | 与 drm_mode_cursor_ioctl 类似,但添加热区。熟悉以支持旧应用(如 X Server)。 |
drm_mode_page_flip_ioctl | drm_plane.c | 处理页面翻转,包括目标 VBlank 和事件。 | 核心翻转函数,确保缓冲区切换原子性。注意标志(如 ASYNC)和目标序列。导出,驱动必须实现 CRTC 的 page_flip 钩子。 |
drm_plane_cleanup | drm_plane.c (隐式引用) | 清理平面资源,包括列表移除和内存释放。 | 销毁钩子的核心。注意在 drm_primary_helper_destroy 中调用。熟悉以避免内存泄漏。 |
注意事项和熟悉建议
- 迁移到原子接口:两个文件强调从遗留(如 set_config)迁移到原子(如 atomic_check/atomic_update)。关键函数如 drm_primary_helper_update 是过渡性的,新驱动应避免。
- 属性和修改器:IN_FORMATS 和 FB_DAMAGE_CLIPS 是标准属性。熟悉 create_in_format_blob(内部函数),它构建修改器 blob。修改器支持是强制性的,即使仅线性格式。
- 原子状态:函数如 drm_plane_helper_check_update 与 drm_atomic_helper_* 协作。熟悉 drm_plane_state 和 drm_crtc_state,以处理缩放/旋转。
- 遗留支持:ioctl 函数(如 drm_mode_cursor_ioctl)处理旧 uAPI。注意与原子模式的混合使用警告(e.g., 不要混用遗留 ioctl 和原子提交)。
- 错误处理:许多函数返回 -EINVAL/-ENOMEM/-EOPNOTSUPP。注意 WARN_ON(如格式计数 >64)和 drm_modeset_lock 以确保线程安全。
- GPU 联系:这些函数间接调用驱动的钩子(如 format_mod_supported),映射到 GPU 硬件平面。熟悉 drm_plane_funcs 和 drm_plane_helper_funcs 以自定义硬件行为。
- 文档和注释:文件有详细 DOC 部分,解释平面类型、属性和损伤。阅读以理解用户空间交互。
在 Linux 内核的 DRM (Direct Rendering Manager) 子系统中,FB_DAMAGE_CLIPS 和 SCALING_FILTER 是与显示平面(Plane)相关的标准属性,定义在 drm_plane.c 中,用于用户空间(如 Wayland、X Server)配置 GPU 显示行为。这两个属性与 GPU 的硬件功能密切相关,分别用于优化显示更新和控制图像缩放质量。以下是对这两个属性的详细解释,包括其定义、用途、实现和使用场景。
1. FB_DAMAGE_CLIPS 属性
定义
- 属性名称:FB_DAMAGE_CLIPS
- 类型:Blob 属性,包含一组 drm_mode_rect 结构,表示帧缓冲区(Framebuffer)中的损伤区域(Damage Regions)。
- 作用:允许用户空间指定帧缓冲区中自上次更新以来发生变化的区域(即“损伤”区域),以优化 GPU 的显示更新。
- 相关代码:
- 定义在 include/drm/drm_plane.h 和 drm_plane.c 的 DOC: damage tracking 部分。
- 关键函数:
- drm_plane_enable_fb_damage_clips:启用该属性。
- drm_plane_get_damage_clips_count:返回损伤矩形数量。
- drm_plane_get_damage_clips:返回损伤矩形数组。
- 辅助迭代器:drm_atomic_helper_damage_iter_init 和 drm_atomic_helper_damage_iter_next(在 drm_atomic_helper.c)。
理解
- 什么是损伤(Damage):
- 损伤是指帧缓冲区中自上次平面更新(或页面翻转,Page Flip)以来发生变化的区域。例如,在桌面环境中,只有窗口移动或内容更新的区域需要重新绘制。
- FB_DAMAGE_CLIPS 是一个提示(Hint),用户空间(如 Wayland 合成器)通过提供损伤矩形告诉内核哪些区域需要更新,减少不必要的渲染或数据传输。
- 数据结构:
- 属性值是一个 Blob,包含 drm_mode_rect 数组,每个矩形定义为:
c
struct drm_mode_rect {__s32 x1, y1; // 左上角坐标(包含)__s32 x2, y2; // 右下角坐标(不包含)};
- 坐标基于帧缓冲区(非固定点格式,区别于 drm_plane_state.src 的 16.16 固定点格式),不能为负值。
- 矩形可以重叠,但文档强烈建议避免重叠以提高效率。
- 属性值是一个 Blob,包含 drm_mode_rect 数组,每个矩形定义为:
- 用途:
- 优化性能:对于虚拟化或远程显示设备(如 USB 显示器、网络传输),只更新损伤区域可显著减少数据传输量。例如,VirtIO-GPU 使用损伤跟踪优化帧更新。
- GPU 渲染效率:GPU 可以仅处理损伤区域的像素,降低渲染负载,节省功耗。
- 用户空间控制:Wayland 等合成器通过 FB_DAMAGE_CLIPS 提供精确的更新区域,确保高效的显示刷新。
- 实现细节:
- 驱动通过 drm_plane_enable_fb_damage_clips 启用该属性:
c
void drm_plane_enable_fb_damage_clips(struct drm_plane *plane) {struct drm_device *dev = plane->dev;struct drm_mode_config *config = &dev->mode_config;drm_object_attach_property(&plane->base, config->prop_fb_damage_clips, 0);}
- 用户空间通过 DRM_IOCTL_MODE_OBJ_SETPROPERTY 设置 FB_DAMAGE_CLIPS,传递 Blob ID。
- 内核验证 Blob 数据并提供迭代器(如 drm_atomic_helper_damage_iter_next)让驱动访问损伤矩形,剪裁到 drm_plane_state.src。
- 驱动可选择全平面更新(忽略损伤)或仅更新损伤区域,但必须保证用户空间渲染整个可见区域,否则可能导致显示错误。
- 驱动通过 drm_plane_enable_fb_damage_clips 启用该属性:
- 注意事项:
- 可选性:FB_DAMAGE_CLIPS 是可选属性,未启用时驱动执行全平面更新。
- 正确性:用户空间必须提供准确的损伤区域,否则可能导致显示内容丢失(如未包含实际变化区域)。
- 驱动自由度:驱动可以读取超过损伤区域的内容(为效率或硬件限制),但用户空间需渲染整个帧缓冲区以避免潜在错误。
- 调试:drm_plane_get_damage_clips 包含警告,检查是否调用 drm_plane_enable_fb_damage_clips:
if (!drm_mode_obj_find_prop_id(&state->plane->base, config->prop_fb_damage_clips->base.id))drm_warn_once(dev, "drm_plane_enable_fb_damage_clips() not called\n");
- 使用场景:
- 虚拟显示设备(如 QEMU 的 VirtIO-GPU)通过损伤跟踪减少网络传输。
- 高性能 GPU(如 Intel、AMD)在多平面合成中优化渲染。
- 嵌入式设备(如 Rockchip)在低功耗场景下减少显示更新开销。
2. SCALING_FILTER 属性
定义
- 属性名称:SCALING_FILTER
- 类型:枚举属性,支持的过滤器类型包括 DRM_SCALING_FILTER_DEFAULT 和 DRM_SCALING_FILTER_NEAREST_NEIGHBOR。
- 作用:允许用户空间指定平面缩放时使用的过滤算法,控制 GPU 硬件缩放的质量。
- 相关代码:
- 定义在 drm_plane.c 的 drm_create_scaling_filter_prop 和 drm_plane_create_scaling_filter_property。
- 关键函数:
- drm_create_scaling_filter_prop:创建枚举属性。
- drm_plane_create_scaling_filter_property:为平面附加属性。
理解
- 什么是缩放过滤:
- 当平面的源矩形(src_w、src_h)与目标矩形(crtc_w、crtc_h)大小不同时,GPU 需要缩放图像。缩放过滤器决定如何插值像素,影响图像质量。
- 支持的过滤器:
- DRM_SCALING_FILTER_DEFAULT:驱动默认的缩放算法(通常是线性插值或硬件优化)。
- DRM_SCALING_FILTER_NEAREST_NEIGHBOR:最近邻插值,适合像素化效果(如游戏)。
- 数据结构:
- 属性是一个枚举类型,值从 drm_prop_enum_list 获取:
static const struct drm_prop_enum_list props[] = {{ DRM_SCALING_FILTER_DEFAULT, "Default" },{ DRM_SCALING_FILTER_NEAREST_NEIGHBOR, "Nearest Neighbor" },};
- 驱动通过 supported_filters 位掩码指定支持的过滤器,必须包括 DEFAULT。
- 属性是一个枚举类型,值从 drm_prop_enum_list 获取:
- 用途:
- 图像质量控制:用户空间(如 Wayland 合成器)可以选择适合场景的缩放算法。例如,视频播放可能选择平滑的线性插值,而像素艺术游戏可能选择最近邻以保留锐利边缘。
- 硬件优化:某些 GPU(如 Intel Skylake+)支持硬件缩放过滤,SCALING_FILTER 允许驱动利用这些功能。
- 用户体验:提供一致的缩放行为,适配不同显示分辨率或缩放比例。
- 实现细节:
- 驱动通过 drm_plane_create_scaling_filter_property 启用属性:
int drm_plane_create_scaling_filter_property(struct drm_plane *plane,unsigned int supported_filters) {struct drm_property *prop = drm_create_scaling_filter_prop(plane->dev, supported_filters);if (IS_ERR(prop))return PTR_ERR(prop);drm_object_attach_property(&plane->base, prop, DRM_SCALING_FILTER_DEFAULT);plane->scaling_filter_property = prop;return 0;}
- 用户空间通过 DRM_IOCTL_MODE_OBJ_SETPROPERTY 设置过滤器值。
- 驱动在 drm_plane_funcs->atomic_check 或 atomic_update 中处理过滤器,配置 GPU 硬件的缩放寄存器。
- supported_filters 必须包含 DRM_SCALING_FILTER_DEFAULT,否则返回 -EINVAL:
if (WARN_ON((supported_filters & ~valid_mode_mask) ||((supported_filters & BIT(DRM_SCALING_FILTER_DEFAULT)) == 0)))return ERR_PTR(-EINVAL);
- 驱动通过 drm_plane_create_scaling_filter_property 启用属性:
- 注意事项:
- 硬件依赖:不是所有 GPU 支持多种缩放过滤器。例如,嵌入式 GPU 可能仅支持默认过滤器。
- 默认值:属性默认值为 DRM_SCALING_FILTER_DEFAULT,确保兼容性。
- 驱动实现:驱动必须在 atomic_check 中验证过滤器是否与硬件兼容,否则返回 -EINVAL。
- 调试:检查 supported_filters 位掩码,确保只包含有效值(当前仅支持 DEFAULT 和 NEAREST_NEIGHBOR)。
- 使用场景:
- 高分辨率显示(如 4K 屏幕)缩放低分辨率内容时,选择高质量过滤器。
- 游戏或像素艺术应用选择最近邻过滤器以保留清晰像素。
- 嵌入式设备(如手机)在缩放 UI 时优化性能和质量。
比较与联系
属性 | FB_DAMAGE_CLIPS | SCALING_FILTER |
---|---|---|
类型 | Blob(drm_mode_rect 数组) | 枚举(DEFAULT、NEAREST_NEIGHBOR) |
用途 | 优化更新区域,减少 GPU 渲染/传输 | 控制缩放算法,优化图像质量 |
启用函数 | drm_plane_enable_fb_damage_clips | drm_plane_create_scaling_filter_property |
用户空间交互 | 通过 DRM_IOCTL_MODE_OBJ_SETPROPERTY 设置 Blob ID | 通过 DRM_IOCTL_MODE_OBJ_SETPROPERTY 设置枚举值 |
硬件依赖 | 依赖 GPU 的损伤处理能力(如 VirtIO-GPU) | 依赖 GPU 的缩放硬件(如 Intel、AMD) |
性能影响 | 减少渲染/传输量,适合虚拟显示 | 影响缩放质量和性能,适合高分辨率显示 |
- 联系:
- 两者都是平面属性,通过 drm_object_attach_property 附加到 drm_plane。
- 都在原子模式设置中起作用,用户空间通过 DRM_IOCTL_MODE_ATOMIC 配置。
- 都依赖 GPU 硬件支持,驱动通过 drm_plane_funcs 的钩子(如 atomic_check)验证。
- 区别:
- FB_DAMAGE_CLIPS 聚焦于优化更新区域,适合网络/低功耗场景;SCALING_FILTER 聚焦于图像质量,适合动态缩放场景。
- FB_DAMAGE_CLIPS 是 Blob,处理复杂区域;SCALING_FILTER 是简单枚举,选择预定义算法。
使用建议
- 用户空间开发:
- 使用 libdrm 获取和设置这些属性。确保检查驱动是否支持(通过 DRM_CAP_ADDFB2_MODIFIERS 或属性存在性)。
- 对于 FB_DAMAGE_CLIPS,合成器需精确计算损伤区域,避免遗漏导致显示错误。
- 对于 SCALING_FILTER,根据应用需求(如视频 vs 游戏)选择合适的过滤器。
- 驱动开发:
- 启用 FB_DAMAGE_CLIPS 时,使用 drm_atomic_helper_damage_iter_* 迭代损伤区域,映射到 GPU 硬件的更新逻辑。
- 实现 SCALING_FILTER 时,在 atomic_check 中验证过滤器支持,配置硬件缩放寄存器。
- 检查硬件手册(如 Intel 或 AMD 的显示引擎文档)以确认支持的损伤/缩放功能。
- 调试:
- 使用 DRM_DEBUG_KMS 日志检查属性设置是否正确。
- 验证 FB_DAMAGE_CLIPS 的矩形坐标是否有效(非负,x2/y2 独占)。
- 确保 SCALING_FILTER 的 supported_filters 包含 DEFAULT。
总结
- FB_DAMAGE_CLIPS:一个 Blob 属性,允许用户空间指定帧缓冲区的变化区域,优化 GPU 渲染和传输效率,特别适合虚拟化或低功耗场景。驱动可选择性更新区域,但用户空间需渲染完整帧缓冲区。
- SCALING_FILTER:一个枚举属性,控制平面缩放的过滤算法,影响图像质量,适合高分辨率或特定视觉需求(如游戏)。驱动必须支持默认过滤器并验证硬件兼容性。
两者通过 drm_plane.c 的函数暴露给用户空间,与 GPU 的显示硬件(如缩放单元、DMA 引擎)直接交互。
三、Android应用层到DRM Plane的流程
1. Android 与 DRM 的交互位置
在 Android 上,SurfaceFlinger / HWC(Hardware Composer HAL) 并不会直接写寄存器去驱动显示,而是通过内核 DRM/KMS 驱动 提供的 ioctl 接口 来完成显存分配、模式设置、atomic 提交等操作。
这些 ioctl 入口大部分在 drivers/gpu/drm/drm_ioctl.c
和 drivers/gpu/drm/drm_mode_object.c
中实现,核心接口是 drm_mode_*
系列。
2. drm_ioctl.c 里和 Android 相关的 ioctl
关键 ioctl(用户态可调用,HWC/Gralloc 会用到的)包括:
资源查询类
DRM_IOCTL_MODE_GETRESOURCES
→ 获取 CRTC / Connector / Encoder 列表DRM_IOCTL_MODE_GETCRTC
/DRM_IOCTL_MODE_GETCONNECTOR
/DRM_IOCTL_MODE_GETENCODER
→ 查询硬件资源状态
缓冲区管理类(Gralloc)
DRM_IOCTL_MODE_CREATE_DUMB
→ 创建 dumb buffer(简单 framebuffer,用于测试或 fallback)DRM_IOCTL_PRIME_FD_TO_HANDLE
/DRM_IOCTL_PRIME_HANDLE_TO_FD
→ buffer 共享(dma-buf 机制),Android Gralloc 常用
显示模式 / 原子操作类(HWC)
DRM_IOCTL_MODE_SETCRTC
→ legacy 模式设置DRM_IOCTL_MODE_PAGE_FLIP
→ 翻页显示(传统方式)DRM_IOCTL_MODE_ATOMIC
→ 原子操作接口(HWC2 通常走这个)
3. Android HWC / Gralloc 与 DRM 的对应关系
Gralloc HAL
负责分配显存 buffer,一般通过 GBM (Generic Buffer Manager) 或 Ion/DMABUF 分配,再通过 PRIME fd 传给 DRM
ioctl 重点是
CREATE_DUMB
,PRIME_*
HWC HAL
负责控制显示输出(overlay 组合、VSync、显示提交)
早期 Android 使用
SETCRTC
+PAGE_FLIP
,现在多数厂商实现 HWC2 时会调用DRM_IOCTL_MODE_ATOMIC
来提交 plane/crtc/connector 的设置
4. DRM 四大对象的 ioctl 操作对应关系
你提到的 CRTC / Connector / Encoder / Plane 这四类对象,在 DRM 内核里都继承自 drm_mode_object,最终都可以通过 drm_mode_*
ioctl 系列操作:
CRTC(显示控制器) →
DRM_IOCTL_MODE_GETCRTC
,SETCRTC
,ATOMIC
Connector(面板/接口,比如 HDMI, DSI) →
DRM_IOCTL_MODE_GETCONNECTOR
,ATOMIC
Encoder(桥接器,CRTC 到 Connector 的转换逻辑) →
DRM_IOCTL_MODE_GETENCODER
Plane(图层,Primary/Overlay/Cursor) →
DRM_IOCTL_MODE_GETPLANE
,ATOMIC
最终 Android HWC 调用 atomic 提交时,是把一组 对象 + 属性值(crtc_id, connector_id, plane_id 以及对应的 fb_id, src/dst rect, mode_id 等)一次性传到内核 → drm_mode_atomic_ioctl()
→ 内核再调用具体厂商驱动的 atomic_check / atomic_commit 来落地。
✅ 总结:
是的,Android 操作 DRM 主要是通过 drm_ioctl.c
中的 drm_mode_*
ioctl 来实现对 crtc / connector / encoder / plane 的操作。
Gralloc → 侧重 buffer 分配 + PRIME fd handle
HWC → 侧重
DRM_IOCTL_MODE_ATOMIC
原子提交
四、Android DRM历史
1. 背景:Android 显示栈
在 Android 中,显示子系统大概分三层:
Gralloc (Graphics Allocator HAL)
用于分配 GPU/显示 buffer(显存或系统内存中的显存缓冲区),供 SurfaceFlinger、HWC 等使用。HWC (Hardware Composer HAL)
负责把多个 Layer 合成,最终交给显示控制器(Display Controller / DRM)显示。SurfaceFlinger
Android 的合成服务,决定哪些图层由 GPU 合成,哪些交给 HWC。
Android 8.0 开始强制 HWC2 接口,Android 10 开始引入 drm_hwcomposer,直接基于 DRM/KMS。
2. DRM Atomic 操作
Linux DRM/KMS 提供两种模式:
Legacy API(早期接口,如
drmModeSetCrtc()
)不支持原子性,单独设置 plane/crtc/connector。
Atomic API(
DRM_IOCTL_MODE_ATOMIC
)支持一次性提交所有显示属性(plane、crtc、connector),保证硬件配置原子更新。
适合 Android 这种多层 buffer 合成的场景。
3. Android HWC 是否使用 DRM Atomic?
是的,现代 Android 的 HWC 主要使用 Atomic API,理由是:
一致性:合成时需要同时更新多个 plane,如果用 legacy API,可能出现 tearing(撕裂)或中间状态。
性能优化:Atomic 支持 非阻塞提交 (async commit) 和 fence (release/acquire fence),这正好对应 Android HWC/Gralloc 的同步机制。
多显示器支持:Atomic 可以一次提交多个 CRTC 的配置,适合手机 + 外接显示。
具体实现:
Android AOSP 有一个
drm_hwcomposer
项目(android_hardware_libhardware/drm_hwcomposer)。它在底层调用 DRM Atomic API 来实现:
drmModeAtomicReq *req = drmModeAtomicAlloc(); drmModeAtomicAddProperty(req, plane_id, FB_ID, fb_id); drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, data);
这就把 HWC2 的
presentDisplay()
映射到 DRM atomic commit。
4. Gralloc 和 DRM 的关系
Gralloc 本身不直接使用 atomic,它主要负责 buffer 分配和 handle/fd 管理(通常基于 GBM 或 ION/DMABUF)。
但是分配的 buffer 会传给 HWC,HWC 在调用
drmModeAtomicCommit
时使用这些 buffer。因此 Gralloc → HWC → DRM Atomic 形成完整链路。
5. 小结
HWC:是 Atomic 的直接用户,通过
drm_hwcomposer
使用 DRM Atomic API。Gralloc:不直接调用 DRM Atomic,只是提供 buffer(fd/dmabuf),最终由 HWC 交给 DRM。
Android 从 Android 10 开始全面切换到 Atomic 模式,之前部分平台可能混用 legacy API。