如果你运气不错,那么你能看到与我相同的显示效果,但是如果(likely())运气差了点,没关系,接下来会详细介绍modetest这些参数的由来。
首先通过--help参数可以查看modetest支持的全部选项,如下:
./modetest --help
usage: /home/alarm/workspace/linux/libdrm-2.4.100/tests/modetest/.libs/lt-modetest [-acDdefMPpsCvw]
Query options:
-c list connectors
-e list encoders
-f list framebuffers
-p list CRTCs and planes (pipes)
Test options:
-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>] set a plane
-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>] set a mode
-C test hw cursor
-v test vsynced page flipping
-w <obj_id>:<prop_name>:<value> set property
-a use atomic API
-F pattern1,pattern2 specify fill patterns
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.
可以看到参数一共分为3类。
Query options:提供查询操作,用于列举出connectors、encoders、framebuffers,CRTCs and planes,未指定参数时默认输出所有信息。
Test options:设定显示测试的参数。
Generic options: 指定打开设备节点,DRM/KMS对用户层来说是一个标准的linux字符设备,其设备节点路径为/dev/dri/cardX、/dev/dri/renderX(之所有有两个设备节点这,涉及到DRM-Master 和 client相关的内容,这里可以简单的认为它们代表用一个设备)
现在我们来看看如何实现一个这样的需求:通过HDMI连接的显示器输出一副分辨率为1920X1080的pattern图像。
这个需求很明确,通过HDMI输出分辨率为1920X1080的图像,Linux DRM/KMS 内核中和显示组件如下图所示:
我们要做的就是找出一组connectors、encoders、framebuffers,CRTCs 和 planes的一个组合,使其能完成我们的需求,步骤如下:
1. 找出与HDMI 相连接的connector
2. 在找到connectors后,要找出可与connector匹配的encoder,
3. 找到connector和encoder可用的CRTC,
4. 为CRTC配置合适plane
5. 为plane创建framebuffers,指定framebuffer大小,并填充pattern图像,framebuffer是唯一有用户层创建的内核对象,其余4个对象均是在DRM driver加载时注册的。
这里所谓的“找到”,就是获取各个组件在内核中的id号,即handle值。
handle有点像文件描述符,是一个32bits的整数,某个linux DRM/KMS内核对象通过handle导出,并在接收到用户的handle后找到该内核对象。
首先来找出与HDMI相关的connector,前面提到modetest具有查询功能,而参数-c list connectors能列举出所以的connector,查询结果如下:
sudo ./modetest -M vc4 -c
Connectors:
id encoder status name size (mm) modes encoders
32 31 connected HDMI-A-1 550x310 39 31
modes:
name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: preferred, driver
...
props:
20 CRTC_ID:
flags: object
value: 140
...
47 0 unknown composite-1 0x0 1 46
...
输出了两组connector的详细(原始log较长,这里只截取关键部分),从log中的关键字可知,id=32的connector是与HDMI相连接的,而该connector是与id=31的encoder相连的,并且通过后面的props列表可以当前连接的CRTC_ID=140. modes列表这列出了connector支持的全部参数配置,即:
CRCT(ID=140) --> ENCODER(ID=31) --> CONNECTED(ID=32) --> HDMI
让我们来回顾一下之前的测试命令:
./modetest -M vc4 -D 0 -a -s 32@140:1920x1080 -P 173@140:1920x1080 -Ftiles
对照一下modetest的参数项: -s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]
即 connector_id = 32,crtc_id =140, mode = 1920x1080,encoder和connector通常是一一对应的,在内核中这两者一般也是一同注册的,并通过函数drm_connector_attach_encoder()关联在一起。
mode我们选择了 1920x1080。
所以connector_id、crtc_id、mode就是这样来的。
列出 encoder:
./modetest -M vc4 -e
Encoders:
id crtc type possible crtcs possible clones
31 140 TMDS 0x00000004 0x00000000
46 0 TVDAC 0x00000004 0x00000000
52 0 Virtual 0x00000002 0x00000000
接下里我们分析-P这个参数的设定,前面已经知道connector_id=32是与crtc_id=140组合的,接下来我们需要为crtc_id=140匹配一个可用的plane id。
列举CRCT和PLANE的命令如下(这里省略了很多内容,因为raspberry Pi 3的vc4 driver支持3个CRCT,每个CRTC又支持10个plane,所以输出内容较多):
./modetest -M vc4 -D 0 -p
CRTCs:
id fb pos size
58 0 (0,0) (0x0)
99 0 (0,0) (0x0)
140 178 (0,0) (1920x1080)
1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: preferred, driver
Planes:
id crtc fb CRTC x,y x,y gamma size possible crtcs
173 0 0 0,0 0,0 0 0x00000004
这里我选择了planes_id=173,选择的依据是possible crtcs = 0x00000004,即bit2=1,表示该plane可用于第3个crcts。
如何理解这里的第3个呢?前面说了CRCT都是通过id来标识的,第3个与crtc=140是关联不上的。
简单的理解是按照上述命令输出的CRCT信息顺序编号,比如第3个crct的id=140。
深层次的原因是kernel中,每成功注册成功一个CRCT后,会把它加入到mode_config->crtc_list中,加入的同时它会获得一个index,而这个index基本上就是按CRCT注册的先后顺序来分配的了(crtc->index = config->num_crtc++)。
最后回到我们下面这个命令:
./modetest -M vc4 -D 0 -a -s 32@140:1920x1080 -P 173@140:1920x1080 -Ftiles
-P选项的命令格式:-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]
即 plane_id=173, crct_id=140
<w>x<h>=1920x1080设置分辨率。
设置后我们的连接状况如下:
PLANE(ID=173, W=1920, H=1080)
|
\ | /
CRCT(ID=140) --> ENCODER(ID=31) --> CONNECTED(ID=32) --> HDMI
buffer的创建是通过函数完成的,大小是从plane相匹配。
framebuffer是在modetest内部分配的,会根据设定的分辨率通过ioctl向驱动程序分配。
剩下的-a 和 -Ftiles两项,
“-a use atomic API“。
-F是指填充一种pattern,后面的值需要在modetest的源码里找,其他可用的值tiles、smpte、plain、gradient。
参考链接:
- 【Linux常见命令】cat命令
cat - concatenate files and print on the standard output cat 命令用于连接文件并打印到标准输出设备上. 用法: 1. cat file 查看 ...
- mysql 5.7 MGR
最近看了一下mysql5.7的MGR集群挺不错的,有单主和多主模式,于是乎搭建测试了一下效果还不错,我指的不错是搭建和维护方面都比较简单.网上绝大多数都是单主模式,当然我这里也是,为了加深印象,特意记 ...
- TCP连接过程及报文解析
可能大家都听过TCP建立连接时需要经历三次握手和四次挥手的. 那么具体的握手挥手的过程是怎么样的呢? 这篇文章就通过WireShark抓包来了解TCP连接建立和断开的过程. 实验方法: 写一段简单的代 ...
- 4.shell基本操作简介
判断一个命令是不是内置命令,可以用type命令 1.printf :冒号 #:〉 test.txt 这里会建立一个空文件test.txt set -o|grep emacs 查看 emacs 模式是 ...
- Linux 下如何产生core文件(core dump设置)
转自:https://blog.csdn.net/star_xiong/article/details/43529637 今天在Linux下调试C程序时,出现段错误,习惯性的ls下当前目录,发现没有生 ...
- Codeforce-Ozon Tech Challenge 2020-D. Kuroni and the Celebration(交互题+DFS)
After getting AC after 13 Time Limit Exceeded verdicts on a geometry problem, Kuroni went to an Ital ...
- Jenkins 源代码管理(SVN)
Subversion 安装插件 1.首先将本地的自动化用例打包上传 svn 2.配置 jenkins 源代码管理(每次执行 jenkins 时,会自动 check-ou t配置地址中的代码到 Jenk ...
- Unix的I/O模型
对于一次I/O操作(以read为例),数据首先被拷贝到内核的某个缓冲区,然后再从内核缓冲区拷贝到应用进程缓冲区. 因此,一次I/O操作通常包含两个阶段: (1) 等待数据准备好 (2) 从内核向进程复 ...
- STL下<algorithm>下的sort函数
定义: sort函数用于C++中,对给定区间所有元素进行排序,默认为升序,也可进行降序排序.sort函数进行排序的时间复杂度为nlog2n,比冒泡之类的排序算法效率要高,sort函数包含在头文件为#i ...
- STM32学习笔记——GPIO
单片机型号STM32F407VET6. 概述 GPIO的分类: 可接受5V输入的(FT),绝大多数引脚都是: 只能接受3.3V输入的(TTa),只有PA4和PA5,就是DAC输出的两个引脚: 其他,包 ...