如果你运气不错,那么你能看到与我相同的显示效果,但是如果(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。
参考链接:
- Springboot以Tomcat为容器实现http重定向到https的两种方式
1 简介 本文将介绍在Springboot中如何通过代码实现Http到Https的重定向,本文仅讲解Tomcat作为容器的情况,其它容器将在以后一一道来. 建议阅读之前的相关文章: (1) Sprin ...
- .Net平台GC VS JVM垃圾回收
前言 不知道你平时是否关注程序内存使用情况,我是关注的比较少,正好借着优化本地一个程序的空对比了一下.Net平台垃圾回收和jvm垃圾回收,顺便用dotMemory看了程序运行后的内存快照,生成内存快照 ...
- IDEA 之 ERROR:端口被占用
问题描述:在IDEA启动javaweb项目中未能成功启动,ERROR:端口已经被使用.但是tomcat并没有被启动. 解决方法: 打开CMD 输入以下命令 netstat -aon | finfstr ...
- python连接mysql数据表查询表获取数据导入到txt中
import pymysql'''连接mysql数据表查询表获取数据导入到txt中'''#查询结果写入数据到txtdef get_loan_number(file_txt): connect = py ...
- JS面向对象编程之对象
在AJAX兴起以前,很多人写JS可以说都是毫无章法可言的,基本上是想到什么就写什么,就是一个接一个的函数function,遇到重复的还得copy,如果一不小心函数重名了,还真不知道从何开始查找错误,因 ...
- TCP连接过程及报文解析
可能大家都听过TCP建立连接时需要经历三次握手和四次挥手的. 那么具体的握手挥手的过程是怎么样的呢? 这篇文章就通过WireShark抓包来了解TCP连接建立和断开的过程. 实验方法: 写一段简单的代 ...
- python 多进程处理 multiprocessing模块
前提: 有时候一个用一个进程处理一个列表中的每个元素(每个元素要传递到一个函数中进行处理),这个时候就要用多进程处理 1 现场案例: 我有一个[ip1,ip2,ip3,.......]这样的列表,我要 ...
- 递归与N皇后问题
递归的基本概念 一个函数调用其自身,就是递归 递归的作用 1) 替代多重循环 2) 解决本来就是用递归形式定义的问题 3) 将问题分解为规模更小的子问题进行求解 一行只能有一个皇后,这个根据游戏规则中 ...
- codeforce 1311 D. Three Integers
In one move, you can add +1 or −1 to any of these integers (i.e. increase or decrease any number by ...
- [bzoj2088]P3505 [POI2010]TEL-Teleportation
洛谷 bzoj 用了分层图的思想 题意 给一张图,要求你再尽可能的多连边,使得从1到2至少要经过5条边 没啥复杂的公式,讲解都在注释里 #include<cstdio> #include& ...