一、drm_framebuffer分析
代码主要作用分析
drm_framebuffer.c 是 Linux 内核 DRM(Direct Rendering Manager)子系统的一部分,主要负责管理帧缓冲区(Frame Buffer,简称 FB)。帧缓冲区是抽象的内存对象,用于存储像素数据,供显示控制器(CRTC)扫描输出到显示设备。它是 DRM 内核模式设置(KMS)功能的核心组件之一,允许用户空间通过特定的 ioctl 接口创建、配置和操作帧缓冲区。
主要功能:
- 帧缓冲区创建与管理:
- 提供接口(如 drm_mode_addfb 和 drm_mode_addfb2)以创建帧缓冲区,支持单平面和多平面格式(通过 drm_mode_fb_cmd2 结构)。
- 验证帧缓冲区参数(如分辨率、像素格式、修饰符等),确保符合硬件和驱动的要求。
- 通过引用计数管理帧缓冲区的生命周期(如 drm_framebuffer_get 和 drm_framebuffer_put)。
- 帧缓冲区操作:
- 支持查询帧缓冲区信息(drm_mode_getfb 和 drm_mode_getfb2)。
- 支持移除帧缓冲区(drm_mode_rmfb),包括从活动使用中移除并释放资源。
- 支持刷新帧缓冲区(drm_mode_dirtyfb),用于手动更新显示设备(如 USB 显示链接或 EDP 自刷新面板)。
- 与硬件的交互:
- 帧缓冲区依赖底层的内存管理器(如 GEM 或 TTM)来分配存储空间。
- 支持像素格式转换、修饰符(modifier)处理(如 Samsung 特定 tiling 格式)以及多平面帧缓冲区。
- 调试与信息输出:
- 提供调试接口(drm_framebuffer_debugfs_init)用于在调试文件系统中输出帧缓冲区信息。
- 通过 DRM_DEBUG_KMS 宏记录调试信息,便于开发者诊断问题。
- 原子模式设置支持:
- 支持原子模式设置(atomic modeset),通过 atomic_remove_fb 函数在移除帧缓冲区时更新相关 CRTC 和平面状态。
- 提供传统(非原子)模式设置的兼容实现(legacy_remove_fb)。
关键数据结构:
- struct drm_framebuffer:表示帧缓冲区对象,包含宽度、高度、像素格式、修饰符、引用计数等信息。
- struct drm_mode_fb_cmd 和 struct drm_mode_fb_cmd2:用户空间传递的帧缓冲区创建参数。
- struct drm_format_info:描述像素格式的元数据,如平面数量、子采样等。
主要函数分析
以下是代码中的主要函数及其作用:
- drm_framebuffer_check_src_coords
- 作用:检查源坐标(src_x, src_y, src_w, src_h)是否在帧缓冲区的边界内。
- 参数:
- src_x, src_y:源区域的起点坐标(以 16.16 固定点格式)。
- src_w, src_h:源区域的宽度和高度。
- fb:帧缓冲区对象。
- 返回值:0 表示有效,-ENOSPC 表示坐标超出边界。
- 用途:确保源坐标合法,防止扫描输出超出帧缓冲区范围。
- drm_mode_addfb
- 作用:通过旧版 ioctl(DRM_IOCTL_MODE_ADDFB)添加帧缓冲区,仅支持 RGB 格式。
- 参数:
- dev:DRM 设备。
- or:旧版帧缓冲区参数(drm_mode_fb_cmd)。
- file_priv:DRM 文件句柄。
- 实现:将旧版参数转换为新版格式(drm_mode_fb_cmd2),调用 drm_mode_addfb2。
- 返回值:0 表示成功,负数表示错误码。
- drm_mode_addfb2
- 作用:通过新版 ioctl(DRM_IOCTL_MODE_ADDFB2)添加帧缓冲区,支持多平面格式和 fourcc 像素格式。
- 参数:
- dev:DRM 设备。
- data:帧缓冲区参数(drm_mode_fb_cmd2)。
- file_priv:DRM 文件句柄。
- 实现:调用 drm_internal_framebuffer_create 创建帧缓冲区,并将其加入文件句柄的帧缓冲区列表。
- 返回值:0 表示成功,负数表示错误码。
- framebuffer_check
- 作用:验证帧缓冲区参数的合法性,包括像素格式、分辨率、修饰符、句柄等。
- 参数:
- dev:DRM 设备。
- r:帧缓冲区参数(drm_mode_fb_cmd2)。
- 实现:
- 检查像素格式是否支持。
- 验证分辨率是否有效。
- 检查每个平面的句柄、pitch 和修饰符。
- 针对特定修饰符(如 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)进行额外验证。
- 返回值:0 表示通过,负数表示错误码。
- drm_internal_framebuffer_create
- 作用:核心函数,用于创建帧缓冲区对象。
- 参数:
- dev:DRM 设备。
- r:帧缓冲区参数(drm_mode_fb_cmd2)。
- file_priv:DRM 文件句柄。
- 实现:
- 验证参数(调用 framebuffer_check)。
- 检查分辨率是否在设备配置的范围内。
- 调用驱动提供的 fb_create 函数创建帧缓冲区。
- 返回值:指向创建的帧缓冲区对象的指针,或错误指针。
- drm_mode_rmfb
- 作用:移除指定的帧缓冲区,从活动使用中移除并释放资源。
- 参数:
- dev:DRM 设备。
- fb_id:帧缓冲区 ID。
- file_priv:DRM 文件句柄。
- 实现:
- 查找帧缓冲区并验证其归属。
- 如果仍有引用,使用工作队列(drm_mode_rmfb_work_fn)异步移除。
- 否则直接释放引用。
- 返回值:0 表示成功,负数表示错误码。
- drm_mode_getfb 和 drm_mode_getfb2
- 作用:查询帧缓冲区信息,分别支持旧版(单平面)和新版(多平面)ioctl。
- 参数:
- dev:DRM 设备。
- data:用户空间传递的查询结构。
- file_priv:DRM 文件句柄。
- 实现:
- 查找帧缓冲区。
- 填充分辨率、像素格式、pitch 等信息。
- 对于非主控进程,返回无效句柄(0)。
- 返回值:0 表示成功,负数表示错误码。
- drm_mode_dirtyfb_ioctl
- 作用:刷新帧缓冲区的受损区域(clip rectangles),用于手动更新显示。
- 参数:
- dev:DRM 设备。
- data:包含 clip 矩形列表的结构。
- file_priv:DRM 文件句柄。
- 实现:
- 验证 clip 矩形数量和格式。
- 调用帧缓冲区的 dirty 回调函数进行刷新。
- 返回值:0 表示成功,负数表示错误码。
- drm_framebuffer_init
- 作用:初始化帧缓冲区对象,分配 ID 并加入设备的管理列表。
- 参数:
- dev:DRM 设备。
- fb:帧缓冲区对象。
- funcs:帧缓冲区操作函数集。
- 实现:
- 设置帧缓冲区的函数集和任务名称。
- 将帧缓冲区加入设备的模式配置列表。
- 返回值:0 表示成功,负数表示错误码。
- drm_framebuffer_remove
- 作用:从所有 CRTC 和平面中移除帧缓冲区,并释放引用。
- 参数:
- fb:帧缓冲区对象。
- 实现:
- 如果设备支持原子模式设置,调用 atomic_remove_fb。
- 否则调用 legacy_remove_fb。
- 最后释放帧缓冲区的引用。
- 用途:在帧缓冲区移除或驱动卸载时清理资源。
- drm_framebuffer_cleanup
- 作用:从设备的管理列表中移除帧缓冲区。
- 参数:
- fb:帧缓冲区对象。
- 实现:从设备的帧缓冲区列表中移除并更新计数。
- drm_framebuffer_debugfs_init
- 作用:初始化调试文件系统接口,输出所有帧缓冲区的信息。
- 参数:
- minor:DRM 次设备。
- 实现:注册调试文件,调用 drm_framebuffer_info 输出信息。
drm_mode_addfb_ioctl
└── drm_mode_addfb
└── drm_mode_addfb2
└── drm_internal_framebuffer_create
├── framebuffer_check
│ ├── fb_plane_width
│ ├── fb_plane_height
│ ├── drm_get_format_info
│ └── __drm_format_info
└── dev->mode_config.funcs->fb_create
drm_mode_addfb2_ioctl
└── drm_mode_addfb2
└── drm_internal_framebuffer_create
├── framebuffer_check
│ ├── fb_plane_width
│ ├── fb_plane_height
│ ├── drm_get_format_info
│ └── __drm_format_info
└── dev->mode_config.funcs->fb_create
drm_mode_rmfb_ioctl
└── drm_mode_rmfb
├── drm_framebuffer_lookup
│ └── __drm_mode_object_find
├── drm_framebuffer_put
└── drm_mode_rmfb_work_fn (异步)
├── drm_dbg_kms
└── drm_framebuffer_remove
├── atomic_remove_fb (原子模式设置)
│ ├── drm_modeset_lock_all_ctx
│ ├── drm_atomic_get_plane_state
│ ├── drm_atomic_add_affected_connectors
│ ├── drm_atomic_set_mode_for_crtc
│ ├── drm_atomic_set_fb_for_plane
│ ├── drm_atomic_set_crtc_for_plane
│ ├── drm_atomic_commit
│ ├── trace_android_vh_atomic_remove_fb
│ └── drm_modeset_backoff
├── legacy_remove_fb (传统模式设置)
│ ├── drm_modeset_lock_all
│ ├── drm_crtc_force_disable
│ └── drm_plane_force_disable
└── drm_framebuffer_put
drm_mode_getfb
├── drm_framebuffer_lookup
│ └── __drm_mode_object_find
├── fb->funcs->create_handle
└── drm_framebuffer_put
drm_mode_getfb2_ioctl
├── drm_framebuffer_lookup
│ └── __drm_mode_object_find
├── drm_gem_handle_create
├── fb->funcs->create_handle
├── drm_gem_handle_delete
└── drm_framebuffer_put
drm_mode_dirtyfb_ioctl
├── drm_framebuffer_lookup
│ └── __drm_mode_object_find
├── copy_from_user
├── fb->funcs->dirty
├── kfree
└── drm_framebuffer_put
drm_fb_release
├── drm_framebuffer_put
└── drm_mode_rmfb_work_fn
├── drm_dbg_kms
└── drm_framebuffer_remove
├── atomic_remove_fb
│ ├── drm_modeset_lock_all_ctx
│ ├── drm_atomic_get_plane_state
│ ├── drm_atomic_add_affected_connectors
│ ├── drm_atomic_set_mode_for_crtc
│ ├── drm_atomic_set_fb_for_plane
│ ├── drm_atomic_set_crtc_for_plane
│ ├── drm_atomic_commit
│ ├── trace_android_vh_atomic_remove_fb
│ └── drm_modeset_backoff
├── legacy_remove_fb
│ ├── drm_modeset_lock_all
│ ├── drm_crtc_force_disable
│ └── drm_plane_force_disable
└── drm_framebuffer_put
drm_framebuffer_init
├── __drm_mode_object_add
└── drm_mode_object_register
drm_framebuffer_free
├── drm_mode_object_unregister
└── fb->funcs->destroy
drm_framebuffer_cleanup
└── list_del
drm_framebuffer_lookup
└── __drm_mode_object_find
drm_framebuffer_remove
├── atomic_remove_fb
│ ├── drm_modeset_lock_all_ctx
│ ├── drm_atomic_get_plane_state
│ ├── drm_atomic_add_affected_connectors
│ ├── drm_atomic_set_mode_for_crtc
│ ├── drm_atomic_set_fb_for_plane
│ ├── drm_atomic_set_crtc_for_plane
│ ├── drm_atomic_commit
│ ├── trace_android_vh_atomic_remove_fb
│ └── drm_modeset_backoff
├── legacy_remove_fb
│ ├── drm_modeset_lock_all
│ ├── drm_crtc_force_disable
│ └── drm_plane_force_disable
└── drm_framebuffer_put
drm_framebuffer_debugfs_init
└── drm_debugfs_create_files
└── drm_framebuffer_info
├── drm_seq_file_printer
├── drm_for_each_fb
└── drm_framebuffer_print_info
├── drm_printf_indent
├── drm_framebuffer_plane_width
├── drm_framebuffer_plane_height
└── drm_gem_print_info
总结
drm_framebuffer.c 是 DRM 框架中用于管理帧缓冲区的核心模块,提供创建、移除、查询和刷新帧缓冲区的功能。它通过用户空间的 ioctl 接口与内核交互,支持原子和传统模式设置,并通过引用计数和锁机制确保线程安全。函数调用图展示了主要函数之间的依赖关系,核心逻辑围绕 drm_internal_framebuffer_create 和 drm_framebuffer_remove,并通过 framebuffer_check 确保参数合法性。调试功能和多平面支持进一步增强了其灵活性,适用于现代显示设备和驱动程序。