文章目录

  • 13.1 DRM简介
  • 13.2 libdrm库介绍
  • 13.3 libdrm库移植
  • 13.4 DRM运行示例
  • 13.4.1 DRM Modeset流程
  • 总结:



13.1 DRM简介

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

DRM是linux内核中负责与显卡交互的管理架构,用户空间很方便的利用DRM提供的API,实现3D渲染、视频解码和GPU计算等工作。是 Linux 内核对显示框架进行分层设计的思想,相较于直接操作 Framebuffer,DRM 框架提供了更多的功能。

DRM驱动框架_ubuntu

Framebuffer,帧缓冲,帧缓冲并不是指的显存上的某一块区域,而是 DRM 抽象出来的一个概念,用 fb_id 表示。 CRTC,对显存进行扫描,将显存图像数据转换成硬件时序信号传输到 Encoder,通常指的是 Display Controller(包括 LCD 控制器)。Plane,图层,有的硬件支持多层合成显示,Plane 是连接 Framebuffer 和 CRTC 的纽带,是内存的搬运工,所有的 Display 控制器(包括 LCD 控制器)至少有一个 Plane。 Encoder,Encoder 与 Connector 相连接,Connector 理解为 hdmi,mipi 等接口的抽象,但是这些接口的时序,协议不同,所有需要 Encoder 将 CRTC 传过来的信号转换成 hdmi,mipi 支持的协议,然后通过 Connector 传输到显示器上。

13.2 libdrm库介绍

libdrm 的作用是将 DRM 内核功能封装成一系列的 open/close/ioctl 等标准接口,应用程序通过调用这些接口来驱动设备实现画面显示。

绝大部分可以分成两类行为,一类是 GEM(Graphics Execution Manager)显存管理,例如显存的分配和释放,另一类是 KMS(Kernel Mode-Setting),显示模式管理,如分辨率等的设置。

DRM驱动框架_ubuntu_02

总之,libdrm,对底层接口进行封装,向上提供通用的 API 接口,主要是各种 ioctl 接口进行封装。 KMS,Kernel Mode Setting,所谓的 Mode Setting,就是更新画面和设置显示参数,更新画面,显示 buffer 的切换,多图层的合成方式,以及每个图层的显示位置,设置显示参数,包括分辨率,刷新率,电源状态等。 GEM,Graphic Execution Manager,主要负责显示 buffer 的分配与释放,也就是 GPU 唯一用到 DRM 的地方。

13.3 libdrm库移植

首先,下载 libdrm 的压缩包,并放在虚拟机中,解压后,在同级目录创建 install 文件夹。
下载链接 https://dri.freedesktop.org/libdrm/

lxc@ubuntu:~/libdrm$ ls
install  libdrm-2.4.89  libdrm-2.4.89.tar.bz2

然后,进入 libdrm-2.4.89 文件夹执行如下命令。

lxc@ubuntu:~/lcd/libdrm$ cd libdrm-2.4.89/
lxc@ubuntu:~/lcd/libdrm/libdrm-2.4.89$ ./configure --prefix=/home/linxincheng/libdrm/install --host=arm-linux CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++  
lxc@ubuntu:~/lcd/libdrm/libdrm-2.4.89$ make
lxc@ubuntu:~/lcd/libdrm/libdrm-2.4.89$ make install

执行完成后可以在 install 文件夹下看到生成的库文件。

lxc@ubuntu:~/libdrm/install$ ls
include  lib  share

然后将 include 和 lib 文件夹中的内容复制到交叉编译器中,这样我们之后编译应用程序时,就只需要在使用交叉编译器时加上 -ldrm 就可以编译使用了 libdrm 的 C 文件了。

lxc@ubuntu:~/libdrm/install/include$ cp * -rfd /opt/buildroot/cortexA7/arm-buildroot-linux-gnueabihf/sysroot/usr/include/
lxc@ubuntu:~/libdrm/install/lib$ cp * -rfd /opt/buildroot/cortexA7/arm-buildroot-linux-gnueabihf/sysroot/usr/lib

13.4 DRM运行示例

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

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

  1. 打开设备文件 open(“/dev/dri/card0”, O_RDWR | O_CLOEXEC);
  2. 获取资源句柄 drmGetVersion(fd);
  3. 获取连接句柄 drmModeGetConnector(fd, conn_id);
  4. 创建FB对象 modeset_create_fb(fd, &buf);
  5. 设置CRTC对象 rmModeSetCrtc(fd, crtc_id, buf.fb_id, 0, 0, &conn_id, 1, &conn->modes[0]);
  6. 资源清零 modeset_destroy_fb(fd, &buf);

13.4.1 DRM Modeset流程

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

fd = open("/dev/ dri/cardo",O_RDWR | o_CLOEXEC);

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

extern drmModeResPtr drmModeGetResources(int fd);

4.3 获取连接句柄connector

drmModeGetConnector(fd, conn_id);

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

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

4.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,drmModeModeInfoPtr mode);

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

static void modeset_cleanup(int fd)

总结:

文章介绍了DRM的由来,驱动框架以及流程示例,,DRM架构符合现代显示设备,但仍有很多老的设备以及软件需要FB支持,在目前DRM框架中,会存在模拟FB设备的代码,参见drivers/gpu/drm/xxx/drv.c文件,会在设备目录下出现:/dev/fb0 中。