linux DRM/KMS 測試工具 modetest、kmscude、igt-gpu-tools (一)
這裡整理幾個在學習Linux DRM/KMS中用到的幾個工具,modetest、kmscude、igt-gpu-tools。
簡介:
modetest
是由libdrm提供的測試程式,可以查詢顯示設備的支援狀況,進行基本的顯示測試,以及設置顯示的模式。
kmscube
是由mesa3d提供和維護,這是一個基於 KMS/GBM/EGL/OPENGL ES2.0 測試用例。
kmscube is a little demonstration program for how to drive bare metal graphics without a compositor like X11, wayland or similar, using DRM/KMS (kernel mode setting), GBM (graphics buffer manager) and EGL for rendering content using OpenGL or OpenGL ES.
igt-gpu-tools
是一個測試DRM drivers的測試工具集
IGT GPU Tools is a collection of tools for development and testing of the DRM drivers.
測試環境和編譯環境:
如未特別註明,所有的程式編譯和測試均是在如下環境中進行的:
硬體環境:raspberry Pi 3 Model B
仍將環境:Linux alarm 5.6.13-1-ARCH #1 SMP Sat May 16 21:58:40 MDT 2020 aarch64 GNU/Linux
modetest
程式碼編譯:
解壓程式碼後,進入目錄執行:
# ./configure
# Make -j4
編譯完成後會在目錄libdrm-2.4.100/tests/modetest下生成 modetest 可執行文件。
modetest示例:
modetest的運行需要root許可權。
首先這裡給出一組顯示示例,命令參數如下:
./modetest -M vc4 -D 0 -a -s 32@140:1920×1080 -P 173@140:1920×1080 -Ftiles
命令執行的console輸出:
程式運行效果如下,通過HDM連接的顯示器整屏的顯示了漸變的斜條紋:
如果你運氣不錯,那麼你能看到與我相同的顯示效果,但是如果(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 550×310 39 31
modes:
name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
1920×1080 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:1920×1080 -P 173@140:1920×1080 -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我們選擇了 1920×1080。
所以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) (1920×1080)
1920×1080 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:1920×1080 -P 173@140:1920×1080 -Ftiles
-P選項的命令格式:-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]
即 plane_id=173, crct_id=140
<w>x<h>=1920×1080設置解析度。
設置後我們的連接狀況如下:
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。
參考鏈接: