Linux内核4.14版本——drm框架分析(1)——drm简介

本文详细介绍了Linux内核中的DRM(Direct Rendering Manager)框架,对比了DRM与传统FB架构的优势,阐述了DRM的发展历程、图形显示框架和驱动框架。内容包括DRM的多图层合成能力、VSYNC支持、统一的GPU和Display管理,以及DRM关键组件如Framebuffer、CRTC、Encoder、Connector等的作用。此外,还给出了简单的DRM模式设置示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. DRM简介(Direct Rendering Manager)

传统linux显示设备驱动开发时,通常使用FB驱动架构,随着显卡性能升级:显示覆盖(菜单层级)、GPU加速、硬件光标,传统FB架构无法很好支持,此外,对于多应用的访问冲突也无法很好控制。在这样的背景下,DRM应用而生。

DRM是linux内核中负责与显卡交互的管理架构,用户空间很方便的利用DRM提供的API,实现3D渲染、视频解码和GPU计算等工作。

1.1 DRM发展历史

(1)1999年Precision Insight公司首次为 XFree86 4.0 Server 开发 DRI 显示框架,用于更好的适配 3DFX 公司显卡,初版DRM代码产出后,接下来的几年时间里,DRM 所支持的显卡列表不断被扩充。

(2)2008年10月Linux kernel 2.6.27 进行了一次重大的源码重组:DRM 的整套源码被放到了/drivers/gpu/drm/目录下,不同的GPU厂商代码也被放到了各自子目录下。

(3)2014年6月Atomic API 被添加到Linux 3.16,许多驱动也都转而使用这些新的 API。

(4)2018年,又有10个基于 atomic 框架的 DRM 新增驱动被添加到Linux kernel。

1.2 DRM架构对比FB架构优势

DRM是目前Linux的主流图形显示框架,相比于传统FB架构,DRM允许多个程序同时使用视频硬件资源,管理多个程序的资源请求、访问,综上所述DRM更能适应日益更新的显示硬件,DRM优势主要体现:

  • DRM原生支持多图层合成,FB原生不支持多层合成。
  • FB不支持VSYNC、DMA-BUF、异步更新和fence机制,但DRM原生都支持。
  • DRM统一管理GPU和Display驱动,让软件升级、维护和管理更加方便。
特性FB架构DRM架构
多图层合成不支持支持
Vsync不支持支持
DMA-BUF不支持支持
异步更新不支持支持
fence机制不支持支持
同一管理驱动,方便维护与升级不支持支持

1.3 DRM图形显示框架

DRM检测到的每个GPU都作为DRM设备,并为之创建一个设备文件/dev/dri/cardX与之连接,从整体架构上来看主要分为三个主要部分

(1)libdrm (接口库)

对底层接口进行封装,向上层提供通用的API接口,主要是对各种IOCTL接口进行封装,便于重用与代码共享。

(2)KMS (Kernel Mode Setting)

正常工作时,需要设置显卡或者图形适配器的模式,主要体现在以下两个方面:

  • 更新画面

显示buffer的切换,多图层的合成方式控制,以及每个图层的显示位置。

  • 设置显示参数

包括分辨率、刷新率、电源状态(休眠唤醒)等。

(3)GEM (Graphics Execution Manager)

提供内存管理方法,主要负责显示buffer的分配和释放。

DRM图形显示框架总览:

1.4 DRM图形显示框架涉及元素

本章节介绍DRM框架中的一些重点模块的功能与在显示链路中的作用,下图为APP调用DRM到屏幕显示的流程框图。

下表对DRM中KMS和GEM两个模型的不同组件进行概述性说明,辅以高通平台代码层级的对应关系说明,以加深架构与流程之间的对应联系。

各部分说明:

1.4.1 DRM Framebuffer

是一块内存区域,可以理解为一块画布,驱动和应用层都能访问它。绘制前需要将它格式化,设定绘制的色彩模式(例如RGB24、YUV 等)和画布的大小(分辨率),不负责显存的分配释放。

1.4.2 CRTC

阴极摄像管上下文(显示控制器),也可以理解为扫描仪(对显示buffer进行扫描,并产生时序信号(RGB timing)的硬件模块)。CRTC对内连接 Framebuffer 地址,对外连接 Encoder,会扫描 Framebuffer 上的内容,叠加上 Planes 的内容,最后传给Encoder。在 rockchip 平台是 SOC 内部 VOP(部分文档也称为 LCDC)模块的抽象。

crtc代码层面的作用:

1)DPMS (Display Power Manage System) 电源状态管理 (crtc_funcs->dpms)。

2)将 Framebuffer 转换成标准的 LCDC Timing ,其实就是一帧图像刷新的过程(crtc_funs->mode_set)。

3)帧切换,即在 VBlank 消影期间,切换 Framebuffer(crtc_funcs->page_flip)。

4)gamma校正值调整(crtc_funcs->gamma_set)。

1.4.3 Encoder

编码器/输出转换器,负责将CRTC输出的timing时序转换成外部设备所需要的信号的模块。它的作用就是将内存的 pixel 像素编码(转换)为显示器所需要的信号(因为画面显示到不同的设备(Display Device)上,需要将画面转化为不同的电信号)。如指 RGB、LVDS、DSI、eDP、HDMI、CVBS、VGA 等显示接口。另外 Encoder 和 CRTC 之间的交互就是我们所说的 ModeSetting,其中包含了前面提到的色彩模式、还有时序(Timing)等。

Encoder代码层面的作用:

1)DPMS (Display Power Manage System) 电源状态管理 (encoder_funcs->dpms)。

2)将 VOP 输出的 lcdc Timing 打包转化为对应接口时序 HDMI TMDS / … (encoder_funcs->mode_set)。

1.4.4 Connector

连接器,指 encoder 和 panel 之间交互的接口部分。对应于物理连接器 (例如 VGA, DVI, FPD-Link, HDMI, DisplayPort, S-Video等) ,它不是指物理线,在 DRM中,Connector 是一个抽象的数据结构,代表连接的显示设备,从Connector中可以得到当前物理连接的输出设备相关的信息。

Connector代码层面的作用:

1)获取上报 热拔插 Hotplug 状态

2)读取并解析屏 (Panel) 的 EDID 信息

1.4.5 Bridge

桥接设备,一般用于注册 encoder 后面另外再接的转换芯片,如 DSI2HDMI 转换芯片。桥接ic所处位置,如下图所示:

1.4.6 Panel

泛指屏,各种LCD, HDMI等显示设备的抽象。用于获取LCD mode参数,并提供LCD休眠唤醒的回调接口,供encoder调用。

1.4.7 Fence

buffer 同步机制,基于内核 dma_fence 机制实现,用于防止显示内容出现异步问题。

1.4.8 Plane

硬件图层, 和 Framebuffer 一样是内存地址。在 rockchip 平台是 SOC 内部 VOP(LCDC)模块 win 图层的抽象。一个Plane代表一个image layer, 最终的image由一个或者多个Planes组成。

plane的主要类型:

  • DRM_PLANE_TYPE_PRIMARY

主要图层,通常用于仅支持RGB格式的简单图层。

  • DRM_PLANE_TYPE_OVERLAY

叠加图层,通常用于YUV格式的视频图层。

  • DRM_PLANE_TYPE_CURSOR

光标图层,一般用于pc系统,用于显示鼠标。

1.4.9 小结

实例解析下 CRTC / Encoder / Connector 的行为:

1)首先 HDMI 驱动检测到电视 Plugin 信号,读出电视的 EDID 信号,获取电视的分辨率信息 (DRM Connector);

2)Userspace 将需要显示的数据填充在 framebuffer 里面,然后通过 libdrm 接口通知 VOP 设备开始显示;

3)接着 VOP 驱动将 framebuffer 里面的数据转换成标准的 LCDC Timing 时序 (DRM CRTC);

4)同时 HDMI 驱动将 HDMI 硬件模块的 LCDC 时序配置与 VOP 输出时序一致,准备将输入的 LCDC Timing 转化为电视识别的 HDMI TMDS 信号 (DRM Encoder)。

名词解释:

  • DRI:Direct Rendering Infrastructure,直接访问硬件接口。
  • EDID:Extended Display Identification Data,扩展显示标识数据,共有128字节。其中包含有关显示器及其性能的参数,包括供应商信息、最大图像大小、颜色设置、厂商预设置、频率范围的限制以及显示器名和序列号的字符串。
  • DDC:Display Data Channel,显示数据通道,顾名思义,它是一个通道,DDC是用来传送EDID信息的。EDID信息包含了显示器需要的128字节,128个字节的附加块可以存储在初始的EDID块之后的EDID扩展块VDIF,这些块包含addtional具体的时序信息。

2. DRM驱动框架

2.1 DRM驱动对象介绍

DRM内部的Objects是组成DRM框架的核心,下图中蓝色部分为物理硬件的抽象,棕色部分则为软件的抽象。其中GEM结构体为:drm_gem_object,其余部分位于结构体drm_mode_object中。

注:drm_panel不属于object范畴,只是为了降低LCD驱动与encoder驱动间的耦合,是一堆回调函数集合。

如上图所示,drm将显示部分抽象出了framebuffer、plane、crtc、encoder、connector五部分。

(1)在同一时刻,一个framebuffer与一个plane动态绑定。

(2)在同一时刻,通常一个或多个plane与一个crtc静态绑定。

(3)在同一时刻,一个crtc与多个encoder动态绑定。

(4)在同一时刻,通常一个encoder与一个connector静态绑定。

2.2 DRM抽象硬件如何关联DRM Object

DRM的objects并不难理解,重要的是如何将实际的硬件与这些object进行关联,下面会以MIPI DSI接口为例进行介绍软件架构与DRM object的对应关系。

其中组件说明:

3. DRM简单示例

DRM代码非常庞大,显卡逻辑也非常复杂,在学习DRM架构时,需要通过实践对DRM的流程进行理解,以达到事半功倍的效果。

下面会以模式设置案例,对DRM架构的流程进行解析。modeset主要流程如下:

3.1 打开DRM设备文件

DRM框架成功加载后,会创建一个设备文件/dev/dri/card0,上层用户应用可以通过该文件节点,获取显卡的各种操作。

fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);

3.2 获取显卡资源句柄

打开DRM设备文件后,通过以下函数获取显卡的资源句柄,进而进行显卡资源的操作。

extern drmModeResPtr drmModeGetResources(int fd);

3.3  获取connectorId

获取了drmModeRes后,获取它的连接对象。

extern drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connectorId);

3.4 创建FrameBuffer

创建FrameBuffer后,然后映射一片内存,对这块内存进行像素数据填充。

static int modeset_create_fb(int fd, struct modeset_dev *dev)

3.5 设置Crtc模式

FB创建成功并进行清0操作,可以在里面填充任何数据,然后设置CRTC后,FB的内容就可以显示在屏幕。

CRTC模式设置函数:drmModeSetCrtc(),参数为:fd、crtc句柄、FB句柄、X\Y坐标等。

int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeInfoPtr mode);

3.6 资源清理工作

显示完成后,GUI会一直运行,一般不必实施资源清理工作。

static void modeset_cleanup(int fd);

4. 本章小结

本文介绍了DRM架构的发展历史、驱动框架以及简单示例,旨在帮助读者了解DRM架构的形成、功能流程实现,DRM代码庞大且复杂,想要深入理解它的内涵,最好的办法就是根据实际需求来进行代码流程梳理,后续章节也会对该部分进行展开讲解。

此外,DRM架构符合功能日益强大的现代显示设备,但仍有很多老的设备以及软件需要FB支持,在目前DRM框架中,会存在模拟FB设备的代码,参见drivers/gpu/drm/xxx/drv.c文件,会在设备目录下出现:/dev/fb0 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值