一、環境資源要求
下載libdrm
Index of /libdrm
這邊使用的是2.4.114版本,版本太高對meson版本要求也很高,為了省事用apt安裝meson就不用太高版本了,1.x版本雖然使用makefile編譯方便但是太老,對應用支持不太好。
https://dri.freedesktop.org/libdrm/libdrm-2.4.114.tar.xz
由于libdrm項目是基于meson構建的,所以需要安裝meson
sudo apt install meson
二、代碼編譯
1、解壓并cd到代碼目錄下?
cd libdrm-2.4.114
2、創建目錄
#建立安裝目錄
mkdir install
#創建編譯目錄
mkdir build
3、創建cross_file.txt文件
#創建并編寫cross_file.txt文件,用于配置交叉編譯環境
vi cross_file.txt
在cross_file.txt添加如下配置項
[binaries]
c = 'arm-linux-gnueabihf-gcc'
cpp = 'arm-linux-gnueabihf-g++'
ar = 'arm-linux-gnueabihf-ar'
strip = 'arm-linux-gnueabihf-strip'[host_machine]
system = 'linux'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'[build_machine]
system = 'linux'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
4、配置編譯選項
# cd到build目錄
cd build
# 配置編譯選項,根據自己平臺將對應平臺的false替換為true
meson --prefix=$(pwd)/../install \--cross-file=../cross_file.txt \-D amdgpu=false \ #amd集顯平臺-D etnaviv=false \ #vivante圖芯gpu支持-D exynos=false \ #三星平臺-D freedreno=false \ #高通平臺-D freedreno-kgsl=false \ #高通平臺-D intel=false \ #intel集顯平臺-D nouveau=false \ #nvdia平臺-D omap=false \ #ti平臺-D radeon=false \ #amd獨顯平臺-D tegra=false \ #nvdia tegra(switch)平臺-D vc4=false \ #博通VC4平臺-D libkms=false \ #drm kms庫-D man-pages=false \ #man手冊-D udev=false \ #udev支持-D valgrind=false \ #內存測試-D cairo-tests=false \ #cairo語言測試-D vmwgfx=false #VMWare圖形驅動支持-D install-test-programs=true \ #安裝測試程序,建議安裝,便于檢測排查問題。
5、編譯安裝
#編譯并安裝
ninja && ninja install
#完成后在../install目錄可以能得到對應的文件
三、環境測試
1、modetest測試
#modetest 參數
modetest -h #幫助Query options:#用于查詢的參數選項-c list connectors #列舉出所有的connectors-e list encoders #列舉出所有的encoders -f list framebuffers #列舉出所有的framebuffers -p list CRTCs and planes (pipes) #列舉出所有的CRTCs和planes Test options:#用于測試的參數選項#-P給CRTC指定plane-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>] set a plane #-s 設置輸出模式,選擇connector和crtc-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>] set a mode -C test hw cursor-v test vsynced page flipping-r set the preferred mode for all connectors-w <obj_id>:<prop_name>:<value> set property-a use atomic API-F pattern1,pattern2 specify fill patternsGeneric options:#指定打開設備、驅動-d drop master after mode set-M module use the given driver-D device use the given deviceDefault is to dump all info.#例子
#-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>]
#-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>] set a plane
modetest -s 37@35:1024x768 -P 33@35:1024x768 #運行成功會有屏幕彩塊顯示
#37是連接器號,通過modetest -c查詢
#兩個35都是crtc的號,通過modetest -p可以查詢到帶分辨率的接口crtc號,以及顯示分辨率。
2、代碼測試
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include <xf86drmMode.h>#define WIDTH 800 //修改為屏幕對應分辨率寬度
#define HEIGHT 600 //修改為屏幕對應分辨率高度int main(int argc, char **argv) {int fd;drmModeRes *resources;drmModeConnector *connector;drmModeEncoder *encoder;drmModeCrtc *crtc;uint32_t *framebuffer;uint32_t handle;uint32_t stride;uint32_t size;int ret;// 打開DRM設備fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);if (fd < 0) {perror("Failed to open DRM device");return 1;}// 獲取資源resources = drmModeGetResources(fd);if (!resources) {perror("Failed to get DRM resources");close(fd);return 1;}// 查找連接for (int i = 0; i < resources->count_connectors; i++) {connector = drmModeGetConnector(fd, resources->connectors[i]);if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0) {break;}drmModeFreeConnector(connector);}if (!connector) {fprintf(stderr, "No connected connector found\n");drmModeFreeResources(resources);close(fd);return 1;}// 查找編碼器encoder = drmModeGetEncoder(fd, connector->encoder_id);if (!encoder) {perror("Failed to get encoder");drmModeFreeConnector(connector);drmModeFreeResources(resources);close(fd);return 1;}// 獲取CRTCcrtc = drmModeGetCrtc(fd, encoder->crtc_id);if (!crtc) {perror("Failed to get CRTC");drmModeFreeEncoder(encoder);drmModeFreeConnector(connector);drmModeFreeResources(resources);close(fd);return 1;}// 計算幀緩沖區大小stride = WIDTH * 4; // 假設每個像素4字節(32位顏色)size = stride * HEIGHT;// 創建幀緩沖區ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMMY, &handle);if (ret < 0) {perror("Failed to create dummy buffer");drmModeFreeCrtc(crtc);drmModeFreeEncoder(encoder);drmModeFreeConnector(connector);drmModeFreeResources(resources);close(fd);return 1;}// 映射幀緩沖區到內存framebuffer = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, handle);if (framebuffer == MAP_FAILED) {perror("Failed to map framebuffer");drmModeFreeCrtc(crtc);drmModeFreeEncoder(encoder);drmModeFreeConnector(connector);drmModeFreeResources(resources);close(fd);return 1;}// 填充幀緩沖區for (int y = 0; y < HEIGHT; y++) {for (int x = 0; x < WIDTH; x++) {uint32_t color = (x * 255 / WIDTH) << 16 | (y * 255 / HEIGHT) << 8 | 255;framebuffer[y * WIDTH + x] = color;}}// 設置CRTCret = drmModeSetCrtc(fd, crtc->crtc_id, handle, 0, 0, &connector->connector_id, 1, &connector->modes[0]);if (ret < 0) {perror("Failed to set CRTC");munmap(framebuffer, size);drmModeFreeCrtc(crtc);drmModeFreeEncoder(encoder);drmModeFreeConnector(connector);drmModeFreeResources(resources);close(fd);return 1;}// 等待用戶輸入printf("Press Enter to exit...\n");getchar();// 恢復原來的CRTCdrmModeSetCrtc(fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &connector->connector_id, 1, &crtc->mode);// 清理資源munmap(framebuffer, size);drmModeFreeCrtc(crtc);drmModeFreeEncoder(encoder);drmModeFreeConnector(connector);drmModeFreeResources(resources);close(fd);return 0;
}
編譯代碼
gcc -o drm_draw main.c -ldrm# 交叉編譯 gcc可替換arm-linux-gnueabihf-gcc, -ldrm前加上drm庫路徑 -L /path/libdrm/lib/ 以及加上include路徑 -I /path/libdrm/include/
?運行代碼
sudo ./drm_draw
四、參考文章
DRM框架與libdrm移植-CSDN博客