文章目录
- 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 框架提供了更多的功能。
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),显示模式管理,如分辨率等的设置。
总之,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主要流程如下:
- 打开设备文件 open(“/dev/dri/card0”, O_RDWR | O_CLOEXEC);
- 获取资源句柄 drmGetVersion(fd);
- 获取连接句柄 drmModeGetConnector(fd, conn_id);
- 创建FB对象 modeset_create_fb(fd, &buf);
- 设置CRTC对象 rmModeSetCrtc(fd, crtc_id, buf.fb_id, 0, 0, &conn_id, 1, &conn->modes[0]);
- 资源清零 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 中。