libdrm移植到arm设备

发布于:2025-02-10 ⋅ 阅读:(44) ⋅ 点赞:(0)

一、环境资源要求

下载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 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.

#例子
#-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;
    }

    // 获取CRTC
    crtc = 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;
        }
    }

    // 设置CRTC
    ret = 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();

    // 恢复原来的CRTC
    drmModeSetCrtc(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博客


网站公告

今日签到

点亮在社区的每一天
去签到