modetest 是由 libdrm 提供的测试程序,可以查询显示设备的特性,进行基本的显示测试,以及设置显示的模式。
我们可以借助该工具来学习 Linux DRM 应用编程,另外为了深入分析 Rockchip DRM driver,有必要先了解一下这个工具的使用方法和内部实现。
本文目录:
一、准备工作
二、modetest 使用示例
1. 查看帮助信息
2. 查看组件的信息
3. 在 HDMI 上显示
4. 在 eDP 上显示
三、编写最简单的 DRM 应用
四、DRM 应用如何呼叫到 Rockchip DRM driver?
五、相关参考
一、准备工作
在 NanoPC T4 + Linux-4.4 上:
接好 eDP 屏以及 HDMI 显示器;
退出所有占用 /dev/dri/card0 的程序;
编译 modetest
$ git clone https://gitlab.freedesktop.org/mesa/drm
$ apt-get install meson
$ meson builddir/
$ ninja -C builddir/ install
二、modetest 使用示例
1. 查看帮助信息
$ modetest -h
usage: modetest [-acDdefMPpsCvrw]
Query options:
-c list connectors
-e list encoders
-f list framebuffers
-p list CRTCs and planes (pipes)
Test options:
...
Generic options:
-d drop master after mode set
-M module use the given driver
-D device use the given device
Default is to dump all info.
2. 查看组件的信息
$ modetest -M rockchip
Encoders:
id crtc type possible crtcs possible clones
76 54 TMDS 0x00000001 0x00000000
78 0 TMDS 0x00000003 0x00000000
80 65 TMDS 0x00000002 0x00000000
Connectors:
...
参数说明:
-M
:用于指定访问 rockchip DRM driver
关键内容:
Encoders / Connectors / CRTCs / Planes 的 id,modetest 通过 id 来用于引用这些组件。
Connectors 的 modes/props:
CRTCs 的 props;
Planes 的 formats/props;
- prop: 任何你想设置的参数,都可以做成 property,是 DRM 驱动中最灵活、最方便的 Mode setting 机制;
modes: 显示模式,mode 里包含分辨率 / 刷新率等显示相关的信息;
各组件的 id:
$ modetest -M rockchip | cut -f1 | grep -E ^[0-9A-Z]|id
Encoders:
id
90, edp encoder
92, hdmi encoder
100, dp encoder
Connectors:
id
91, edp connector
93, hdmi connector
101, dp connector
CRTCs:
id
64, vop crtc
83, vop crtc
Planes:
id
58
61
65
68
80
84
Frame buffers:
id
3. 在 HDMI 上显示
$ modetest -M rockchip -s 93@64:1920x1080
$ modetest -M rockchip -s 93@64:#1 // 相同的效果
参数说明:
-s [,][@]:[#][-][@
]
:用于在指定的 pipeline 上以某个 mode 显示某个 pattern 的画面。
93
:HDMI connector id
64
:某个 VOP 的 crtc id
1920x1080
:显示 mode;
HDMI connector 下其他可选的 mode:
#0 1920x1080 60.00
#1 1920x1080 59.94
#2 1920x1080i 30.00
#3 1920x1080i 29.97
...
#24 640x480 60.00
#25 640x480 59.94
#26 720x400 70.08
显示效果:
点击查看大图
4. 在 eDP 上显示
$ modetest -M rockchip -s 91@83:1920x1080
参数说明:
91
:eDP connector id
83
:另外一个 VOP 的 crtc id
1920x1080
:显示 mode;
显示效果:
点击查看大图
三、编写最简单的 DRM 应用
主程序:
int main(int argc, char **argv)
{
int fd;
drmModeConnector *conn;
drmModeRes *res;
uint32_t conn_id;
uint32_t crtc_id;
// 1. 打开设备
fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
// 2. 获得 crtc 和 connector 的 id
res = drmModeGetResources(fd);
crtc_id = res->crtcs[0];
conn_id = res->connectors[0];
// 3. 获得 connector
conn = drmModeGetConnector(fd, conn_id);
buf.width = conn->modes[0].hdisplay;
buf.height = conn->modes[0].vdisplay;
// 4. 创建 framebuffer
modeset_create_fb(fd, &buf);
// 5. Sets a CRTC configuration,这之后就会开始在 crtc0 + connector0 pipeline 上进行以 mode0 输出显示
drmModeSetCrtc(fd, crtc_id, buf.fb_id, 0, 0, &conn_id, 1, &conn->modes[0]);
getchar();
// 6. cleanup
...
return 0;
}
modeset_create_fb():
该函数用于分配 framebuffer,目前不需要太关心,大致就是 3 个步骤:
- Allocating memory;Preparing a mapping;Mapping memory;
运行效果:
程序运行后,eDP 屏显示全屏白色,等待用户输入按键;当用户按下任意按键后,程序退出,显示黑屏。
四、DRM 应用如何呼叫到 Rockchip DRM driver?
drmModeSetCrtc() 到 CRTC driver:
点击查看大图
每一个 DRM CRTC Driver(例如 Rockchip VOP driver) 里都会定义一个 struct drm_crtc_funcs 结构体,其中的 .set_config 都指向 drm_atomic_helper_set_config(),接下来就是 DRM core 开始工作了。
五、相关参考
《RK3399 探索之旅 / Display 子系统 / 基础概念》
小龙兄的博客:https://blog.csdn.net/hexiaolong2009/article/details/83721242
nvidia 的文档:https://docs.nvidia.com/drive/nvvib_docs
Linux man 手册:man 7 drm
思考技术,也思考人生
要学习技术,更要学习如何生活。
你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。
对 嵌入式系统 (Linux、RTOS、OpenWrt、Android) 和 开源软件 感兴趣,关注公众号:嵌入式 Hacker。
觉得文章对你有价值,不妨点个 在看和赞。