news 2026/10/31 4:17:09

drm常见知识整理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
drm常见知识整理

在drm框架内,显示的一般流程如下:
内存 (Framebuffer) → Plane (图层配置与合成) → CRTC (时序生成与扫描输出) → Encoder → Connector → 显示器

plane

代表一个图像源。在扫描输出过程中可与crtc混合或叠加在其上方。 其从drm_framebuffer对象获取输入数据。其指定该图像的裁剪和缩放,以及它在drm_crtc表示显示管线可见区域上的放置位置。 其还可具有其他属性,这些属性指定像素的定位和混合方式,如旋转或Z轴位置。所有这些属性都存储在drm_plane_state中。

类型 说明

DRM 定义了三种标准 Plane 类型,驱动根据硬件能力进行分配:

  • Primary 主图层,每个 CRTC 必须有一个。通常支持全屏显示,是页面翻转的主要对象。
  • Cursor 光标图层,用于硬件光标。尺寸通常较小(如 64×64),支持异步更新,延迟极低。
  • Overlay 叠加图层,用于视频播放、UI 合成等。数量因硬件而异,能力也各不相同(是否支持缩放、旋转等)。

代码说明

drm_plane由kms驱动分配、初始化、注册 调用drm_universal_plane_init()
cursor overlay plane是可选择的,所有的驱动应该提供一个primary plane为每一个crtc。特殊的plane通过调用drm_crtc_init_with_planes()函数与crtc进行关联

struct drm_plane_state {

struct drm_plane *plane; //指向plane对象 struct drm_crtc *crtc; //当前绑定的crtc,NULL表示禁用,不能直接赋值,需要使用函数drm_atomic_set_crtc_for_plane() struct drm_framebuffer *fb; //当前绑定的framebuffer,不能直接赋值,需要使用drm_atomic_set_fb_for_plane() struct dma_fence *fence; //在扫描输出fb前可选择fence等待,当用户使用显示fence时atomic fence将会被设置 int32_t crtc_x; //plane显示在crtc左侧位置 int32_t crtc_y; //plane显示在crtc上侧位置 uint32_t crtc_w, crtc_h; //crtc可见位置的高度和宽度 uint32_t src_x; //平面内可见部分的左侧位置 uint32_t src_y; //平面内可见部分的上侧位置 uint32_t src_h, src_w; //平面可见位置的高度和宽度 u16 alpha; //平面的不透明度,0表示完全透明,0xffff表示完全不透明 uint16_t pixel_blend_mode; //alpha混合方式选择,描述当前平面的像素如何与背景合成 unsigned int rotation; //平面的旋转 unsigned int zpos; //平面在crtc上的优先级 unsigned int normalized_zpos; //zpos的归一化值:唯一,范围从0到N-1,其中N是给定crtc的活动平面数 enum drm_color_encoding color_encoding; //非RGB格式的颜色编码 enum drm_color_range color_range; //非RGB格式的颜色范围 struct drm_property_blob *fb_damage_clips;//平面帧缓冲区中自上次平面更新以来发生变化的区域 struct drm_rect src, dst; //平面的剪切源/目地坐标 bool visible; //平面是否可见,与fb和crtc是否赋值无关,与裁剪相关 struct drm_crtc_commit *commit; //跟踪挂起的提交,以防止在空闲条件后使用,并用于异步平面更新。可能为空。 struct drm_atomic_state *state; //指向drm_atomic_state对象 };

plane驱动的控制回调函数

struct drm_plane_funcs { int (*update_plane)(struct drm_plane *plane,struct drm_crtc *crtc, struct drm_framebuffer *fb,int crtc_x, int crtc_y,unsigned int crtc_w, unsigned int crtc_h,uint32_t src_x, uint32_t src_y,uint32_t src_w, uint32_t src_h, struct drm_modeset_acquire_ctx *ctx); int (*disable_plane)(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx); void (*destroy)(struct drm_plane *plane); void (*reset)(struct drm_plane *plane); int (*set_property)(struct drm_plane *plane, struct drm_property *property, uint64_t val); struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane); void (*atomic_destroy_state)(struct drm_plane *plane, struct drm_plane_state *state); int (*atomic_set_property)(struct drm_plane *plane,struct drm_plane_state *state,struct drm_property *property, uint64_t val); int (*atomic_get_property)(struct drm_plane *plane,const struct drm_plane_state *state,struct drm_property *property, uint64_t *val); int (*late_register)(struct drm_plane *plane); void (*early_unregister)(struct drm_plane *plane); void (*atomic_print_state)(struct drm_printer *p, const struct drm_plane_state *state); bool (*format_mod_supported)(struct drm_plane *plane, uint32_t format, uint64_t modifier); };
  • update_plane:是为给指定的crtc和fb启用和配置plane的入口点,不能用来禁用plane
  • disable_plane: 这是禁用plane的入口点,DRM调用此方法响应帧缓冲区ID设置为0DRM_USDMODE_SETPLANE的调用
  • destory:清空plane资源
  • reset:重置plane硬件,软件状态重置成off.只能通过drm_mode_config_reset()函数来调用
  • set_property: 这个是更新plane属性的入口函数
  • atomic_duplicate_state:复制plane当前原子状态并返回
  • atomic_destroy_state: 销毁一个拷贝的state
  • atomic_set_property:对驱动程序私有属性值进行解码,并将解码后的值存储到传入的状态结构中。set_property接口一次只能设置单个属性,改动可能立即生效但缺乏同步保障;原子接口则把多个属性打包到一个请求里,通过 drmModeAtomicCommit() 统一校验和提交,保证同一帧内一致生效
  • atomic_get_property:读取plane的私有属性。此函数不能直接调用,需要使用drm_atomic_plane_get_property()
  • late_register:用于注册额外的用户空间接口,将会在驱动加载后面由drm_dev_register()调用
  • early_unregister:此函数与上面的函数对应,用于卸载上面函数注册的用户空间接口。由 drm_dev_unregister()调用

plane结构体定义

struct drm_plane { struct drm_device *dev; //plane属性哪个drm设备 struct list_head head; //在设备上所有的plane列表 char *name; //name可读,由驱动进行修改 struct drm_modeset_lock mutex; //锁 struct drm_mode_object base; //base对象 uint32_t possible_crtcs; //此plane可以使用的crtc uint32_t *format_types; //此plane支持的format unsigned int format_count; //格式数组大小 bool format_default; // uint64_t *modifiers; unsigned int modifier_count; struct drm_crtc *crtc; //绑定的crtc仅对非原子操作有交,原子操作此为NULL struct drm_framebuffer *fb; //绑定的fb仅对非原子操作有交,原子操作此为NULL struct drm_framebuffer *old_fb; const struct drm_plane_funcs *funcs; //plane控制回调函数 struct drm_object_properties properties; //plane的属性 enum drm_plane_type type; //plane type unsigned index; //在mode_config内部位置,可以当数组下标使用 const struct drm_plane_helper_funcs *helper_private; struct drm_plane_state *state; //当前plane的atomic状态 struct drm_property *alpha_property; //plane可选择的alpha属性 struct drm_property *zpos_property; //plane可选择的zpos属性 struct drm_property *rotation_property; //plane可选择的rotation属性 struct drm_property *blend_mode_property; //plane可选择的像素混合模式,代表像素与背景如何合成 struct drm_property *color_encoding_property; //可选择的COLOR_ENCODING模式,用于非rgb模式 struct drm_property *color_range_property; //可选择的COLOR_RANGE模式,用于非rgb模式 };

crtc

说明

drm_crtc 是显示控制器硬件的抽象,它负责从内存中读取像素数据,并生成带有正确时序的视频信号。

核心职责

  • 生成显示时序:这是 CRTC 最根本的任务。它根据 drm_display_mode(包含像素时钟、水平/垂直同步参数、前后沿等)来驱动硬件,产生符合显示器要求的行同步(HSYNC)和场同步(VSYNC)信号,确保画面稳定。
  • 管理扫描输出与页面翻转:CRTC 负责在垂直消隐期间切换当前扫描输出的 Framebuffer,实现无撕裂的页面翻转。这是合成器实现流畅动画和视频播放的基础。
  • 驱动图层合成:CRTC 与一个或多个 Plane 绑定。它负责将 Plane 上的内容(可能经过缩放、色彩空间转换等)合成为最终的扫描输出画面。一个 CRTC 通常对应一个物理显示管道。
  • 执行模式设置:当用户空间请求更改分辨率或刷新率时,CRTC 负责执行 mode_set 操作,重新配置硬件时序发生器。这个过程通常需要先关闭输出,再重新配置,最后重新使能。
  • 管理电源状态:CRTC 参与 DPMS(Display Power Management Signaling)电源管理。它可以在空闲时关闭扫描输出,以节省功耗。

与其他对象的关系

  • 与 Plane:一个 CRTC 可以绑定多个 Plane(主图层、光标层、叠加层)。CRTC 负责在扫描输出时,将这些 Plane 的内容按 Z 序合成为最终画面。
  • 与 Encoder:一个 CRTC 可以连接到一个或多个 Encoder。当连接多个 Encoder 时,可以实现“克隆显示”(同一画面输出到多个接口)。
  • 与 Connector:CRTC 不直接感知 Connector 的存在,它只负责生成信号。Connector 负责物理接口和显示器能力,两者通过 Encoder 间接关联。
  • 与用户空间:CRTC 是 KMS 中暴露给用户空间的核心对象。合成器通过它来设置显示模式、执行页面翻转、配置 Plane 属性,从而完成整个显示画面的更新。
    为了创建一个crtc,kms驱动需要申请、初始化、注册drm_crtc结构体。通过调用drm_crtc_init_with_planes()

crtc回调函数

struct drm_crtc_funcs { void (*reset)(struct drm_crtc *crtc); int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height); int (*cursor_set2)(struct drm_crtc *crtc, struct drm_file *file_priv,uint32_t handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y); int (*cursor_move)(struct drm_crtc *crtc, int x, int y); int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,uint32_t size, struct drm_modeset_acquire_ctx *ctx); void (*destroy)(struct drm_crtc *crtc); int (*set_config)(struct drm_mode_set *set, struct drm_modeset_acquire_ctx *ctx); int (*page_flip)(struct drm_crtc *crtc,struct drm_framebuffer *fb,struct drm_pending_vblank_event *event,uint32_t flags, struct drm_modeset_acquire_ctx *ctx); int (*page_flip_target)(struct drm_crtc *crtc,struct drm_framebuffer *fb,struct drm_pending_vblank_event *event,uint32_t flags, uint32_t target, struct drm_modeset_acquire_ctx *ctx); int (*set_property)(struct drm_crtc *crtc, struct drm_property *property, uint64_t val); struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc); void (*atomic_destroy_state)(struct drm_crtc *crtc, struct drm_crtc_state *state); int (*atomic_set_property)(struct drm_crtc *crtc,struct drm_crtc_state *state,struct drm_property *property, uint64_t val); int (*atomic_get_property)(struct drm_crtc *crtc,const struct drm_crtc_state *state,struct drm_property *property, uint64_t *val); int (*late_register)(struct drm_crtc *crtc); void (*early_unregister)(struct drm_crtc *crtc); int (*set_crc_source)(struct drm_crtc *crtc, const char *source); int (*verify_crc_source)(struct drm_crtc *crtc, const char *source, size_t *values_cnt); const char *const *(*get_crc_sources)(struct drm_crtc *crtc, size_t *count); void (*atomic_print_state)(struct drm_printer *p, const struct drm_crtc_state *state); u32 (*get_vblank_counter)(struct drm_crtc *crtc); int (*enable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc); };
  • reset:重置crtc硬件并将软件状态设置为off,这个函数不能被直接调用,需要通过drm_mode_config_reset()
  • cursor_set:更新cursor图像,光标位置相对于crtc,可以部分或者完全位于可见区域之外
  • cursor_set2:更新光标图像,包括热点信息。其它工作方式与cursor_set完全相同
  • cursor_move:更新光标位置,此函数目前已被弃用
  • gamma_set:在crtc上设置gamma
  • destroy:清空crtc资源
  • set_config:这是crtc模式的主要入口,原子调用由drm_atomic_helper_set_config()
  • page_flip:翻页是一种同步机制,在垂直消隐期间用新的帧缓冲区替换CRTC扫描出的帧缓冲,避免撕裂
  • page_flip_target:与page_flip相同,但有一个额外的参数指定绝对目标垂直空白期
  • set_property:这是更新crtc属性的基本入口点,这个回调函数是可选择的
  • atomic_duplicate_state:拷贝当前crtc的原子状态并返回
  • atomic_destroy_state:用以消毁上面函数生成的对象
  • atomic_set_property:原子设置crtc私有属性,可以一次性设置多个属性
  • atomic_get_property:读取crtc编译的私有属性,不能被直接调用需要使用drm_atomic_crtc_get_property()此函数来实现
  • late_register:这是个可选择的钩子被用来注册额外的用户空间接口

encoder

简介

encoder连接crtc与connector,从crtc获取像素数据,
drm_encoder 的核心作用是在 CRTC(显示控制器)与 Connector(物理接口)之间进行信号转换与路由。
它负责把 CRTC 产生的像素数据,转换成特定显示接口(如 HDMI、LVDS)所需的电信号格式

具体的功能角色

  • 信号转换器:这是它最本质的功能。它根据 encoder_type(如 DRM_MODE_ENCODER_TMDS, DRM_MODE_ENCODER_LVDS)来适配不同的物理层协议,实现“像素数据 → 符合接口标准的电信号”的转变。
  • 路由与连接限制:Encoder 是 CRTC 和 Connector 之间的“插线板”。它的 possible_crtcs 字段决定了它能接受哪些 CRTC 的数据;而一个 CRTC 也可以驱动多个 Encoder,从而实现“克隆显示”(同一画面输出到多个接口)

其功能回调函

struct drm_encoder_funcs { void (*reset)(struct drm_encoder *encoder); void (*destroy)(struct drm_encoder *encoder); int (*late_register)(struct drm_encoder *encoder); void (*early_unregister)(struct drm_encoder *encoder); };
  • reset
    重启encoder硬件并将软件状态设置成off
  • destroy
    清空encoder资源
  • late_register
    这是一个可选择的沟子被用于注册额外的用户空间接口
  • early_unregister
    此函数用于释放上面函数产生内存

结构体定义

struct drm_encoder { struct drm_device *dev; struct list_head head; struct drm_mode_object base; char *name; int encoder_type; unsigned index; uint32_t possible_crtcs; uint32_t possible_clones; struct drm_crtc *crtc; struct drm_bridge *bridge; const struct drm_encoder_funcs *funcs; const struct drm_encoder_helper_funcs *helper_private; };
  • dev:父drm device
  • head:链表管理
  • base: base kms对象
  • encoder_type:编码类型
    • DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A.
    • DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort.
    • DRM_MODE_ENCODER_LVDS for display panels, or in general any panel with a proprietary parallel connector.
    • DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video, Component, SCART).
    • DRM_MODE_ENCODER_VIRTUAL for virtual machine displays
    • DRM_MODE_ENCODER_DSI for panels connected using the DSI serial bus.
    • DRM_MODE_ENCODER_DPI for panels connected using the DPI parallel bus.
    • DRM_MODE_ENCODER_DPMST for special fake encoders used to allow mutliple DP MST streams to share one physical encoder.
  • index :位于mode_config的位置
  • possible_crtcs:潜在的绑定crtc的掩码
  • crtc:目前绑定的crtc
  • funcs:控制回调函数
  • helper_private:中间层私有数据

bridge

简介

drm_bridge 是一个表示编码器链中中间硬件设备的抽象对象。它的核心作用是解决单个 drm_encoder 无法完整描述复杂显示输出链的问题。当 SoC 的显示控制器输出信号后,可能还需要经过一系列外部芯片(如 HDMI 电平转换器、MIPI DSI 转 eDP 芯片等)才能最终驱动屏幕时,drm_bridge 就派上了用场。它允许将这些中间设备串联成链:encoder —> bridge B —> bridge A

具体作用体

  • 参与显示流水线操作:一旦与 encoder 关联,bridge 就会参与 mode_set、enable、disable 等显示控制流程。驱动程序通过 drm_bridge_funcs 中定义的回调函数,在合适的时机对桥接芯片进行配置。
  • 实现级联与链式调用:多个 bridge 可以通过 next 指针链接起来。DRM 框架提供了一系列链式辅助函数(如 drm_bridge_chain_enable),会按照正确的顺序(从靠近 encoder 的到远离的)遍历整条链,调用每个 bridge 的对应操作,确保信号经过的所有中间设备都被正确使能。
  • 对用户空间透明:与 drm_panel 类似,drm_bridge 不是像 CRTC、Plane 或 Connector 那样的 drm_mode_object。它对用户空间不可见,纯粹是内核驱动用来管理硬件的内部钩子。

其回调函数定义

struct drm_bridge_funcs { int (*attach)(struct drm_bridge *bridge); void (*detach)(struct drm_bridge *bridge); enum drm_mode_status (*mode_valid)(struct drm_bridge *bridge, const struct drm_display_mode *mode); bool (*mode_fixup)(struct drm_bridge *bridge,const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); void (*disable)(struct drm_bridge *bridge); void (*post_disable)(struct drm_bridge *bridge); void (*mode_set)(struct drm_bridge *bridge,const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode); void (*pre_enable)(struct drm_bridge *bridge); void (*enable)(struct drm_bridge *bridge); void (*atomic_pre_enable)(struct drm_bridge *bridge, struct drm_atomic_state *state); void (*atomic_enable)(struct drm_bridge *bridge, struct drm_atomic_state *state); void (*atomic_disable)(struct drm_bridge *bridge, struct drm_atomic_state *state); void (*atomic_post_disable)(struct drm_bridge *bridge, struct drm_atomic_state *state); };

connector

简介

drm_connector 是显示器(或显示端点)的抽象对象,它负责管理物理接口的连接状态与显示能力。kms驱动必须:为一个显示接收器 创建、初始化、注册、绑定一个drm_connector,connector必须 绑定一个encoder以便使用

核心职责

  • 探测与报告连接状态:这是它最动态的功能。通过 detect 回调或热插拔(HPD)中断,内核能感知显示器是否插入或拔出。状态(已连接/未连接/未知)会报告给用户空间。它必须被附加到一个 Encoder 上才能工作,通常是一对一的关系。
  • 管理显示能力(EDID):当显示器连接后,Connector 负责通过 I2C 总线(DDC)读取其 EDID 数据。这些数据包含了显示器的原生分辨率、刷新率、支持的模式列表以及物理尺寸,是内核构建可用显示模式列表的基础。
    承载标准属性:Connector 是内核向用户空间暴露控制接口的载体。它包含一系列标准属性,例如:
    • DPMS:控制电源状态(开/待机/挂起/关)。
    • EDID Blob:向用户空间提供原始 EDID 数据。
    • Content Protection (HDCP):用于请求和报告内容保护状态。
    • HDR Metadata:用于传递 HDR 元数据。
    • 区分连接器类型:通过 connector_type(如 HDMI-A、DisplayPort、eDP、LVDS)来标识物理接口类型。驱动必须为每个显示端点创建并注册一个 Connector 实例
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/25 2:00:22

Java后台集成AgentScope Harness:多智能体AI服务无缝接入实践

做管理后台集成 AI 这件事,我一开始也没底。团队技术栈定死在 Java Spring Boot 3 RuoYi-Vue-Plus,但业务方要的却是多智能体的事:客服回复草稿、工单自动分类、运营数据解读、跨角色联合决策。这些需求拆开看,哪一个都不是简单…

作者头像 李华
网站建设 2026/10/23 15:10:43

前端组件库文档自动化:基于AST解析的源码到Markdown生成方案

我入行做前端也有好多年了,一个感受特别深:写框架难,给框架写文档更难。开源组件库、企业级中后台框架、以及各种自研的UI基础设施,代码写得再漂亮,文档一旦跟不上,开发者体验瞬间归零。而文档维护最痛苦的…

作者头像 李华
网站建设 2026/10/24 21:56:11

需求调研实战指南:从访谈技巧到需求优先级排序的闭环方法

1. 所有人都被指错了方向:需求调研的真正起点不是"问"干需求调研这行久了,你会发现一个特别讽刺的现象:绝大多数项目开始前的调研,其实都像是在验货,根本不是在挖需求。我接过最典型的一个活是给一家中型物流…

作者头像 李华
网站建设 2026/10/24 13:28:22

Aras Open PLM系统管理手册:架构、权限、工作流与备份恢复实战指南

简介:《Aras Open PLM 系统管理手册》是一份面向企业PLM管理员、实施工程师及制造企业IT人员的系统管理指南,重点解决Aras PLM平台日常运维、权限配置与数据建模问题。内容从用户管理入手,依次讲解用户账户建立与锁定、登录认证方式&#xff…

作者头像 李华
网站建设 2026/10/26 0:06:35

vLLM-Omni 上的 Sol-Attn:帧级稀疏注意力破解视频生成显存难题

跑视频生成功能的时候,最让人崩溃的不是模型选型,而是显存和速度的双重绞杀。vLLM-Omni 本身就是冲着多模态推理去的,语音、图像、视频都能塞进同一个服务框架里,但视频生成和视频理解不一样,生成过程每一帧都会作为新…

作者头像 李华
网站建设 2026/10/31 4:00:27

Vue3商城前端工程化实践:从脚手架到上线的完整链路

简介:这是一套基于Vue 2构建的轻量级前端商城项目,面向前端初学者与Vue进阶学习者,帮助快速掌握单页应用(SPA)开发核心流程与工程化实践。项目采用Vue Vue Router Axios技术栈,完整实现商品展示、路由跳转…

作者头像 李华