如果你运气不错,那么你能看到与我相同的显示效果,但是如果(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网络基础】 DNS:介绍、作用、解析原理
1. DNS是什么? DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去+·记住能够被机器直接读 ...
- mac OS 搭建PHP项目开发环境
系统 macOS Mojave 版本10.14.6 mac OS 自带Apache和PHP 非常便利 sudo apachectl -v //查看apache版本 php -v //查看php版本 启 ...
- time wait 整理
目录 状态转换图 1.谁会进入time wait状态: 主动发起断开连接的一方调用close()函数发送FIN并进入FIN WAIT 1状态,当收到对面反馈的ack之后会进入FIN WAIT2状态.之 ...
- mysql 5.7 MGR
最近看了一下mysql5.7的MGR集群挺不错的,有单主和多主模式,于是乎搭建测试了一下效果还不错,我指的不错是搭建和维护方面都比较简单.网上绝大多数都是单主模式,当然我这里也是,为了加深印象,特意记 ...
- Codeforces Round #622 (Div. 2) 1313 A
Tired of boring office work, Denis decided to open a fast food restaurant. On the first day he made ...
- 洛谷 2016 战略游戏(树形DP)
题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题. 他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能 ...
- vue2.0那些坑之使用elementUI后v-on:click事件不生效问题
最近在维护vue2.0的项目,遇到了不少坑,在这里说下引用elementui之后,使用v-on:click绑定点击事件无效的情况,如下图: 我想阻止冒泡事件,发现无效.这里将@click换成了@cli ...
- 学习bootstarp第一天
一.下载bootstarp(https://v3.bootcss.com/),解压并将文件放入自己项目里去使用即可 二.安装bootstarp <!DOCTYPE html> <h ...
- 李婷华 201771010113 《面向对象程序设计(java)》第一周学习总结
第一部分:课程准备部分 填写课程学习 平台注册账号, 平台名称 注册账号 博客园:www.cnblogs.com 薄荷蓝莓 程序设计评测:https://pintia.cn/ 1957877441@q ...
- learn from collection framework design
最难忍受的痛苦,也许是想干一件事情而又不去干.--罗曼·罗兰 前言 本篇文章算是拾人牙慧吧,偶尔谷歌到一个能很好把collection framework design讲好的文档,一是为了总结提升,也 ...