libdrm-modetest原理及图显系统验证方法

linux平台普遍采用的DRM软件架构中,不仅包含了内核空间驱动层的代码,而且提供应用层的支撑库libdrm。libdrm基于DRI协议通过ioctl与2D图显驱动进行交互,配置图显处理器以及HDMI、MIPI、LVDS等编解码单元。

from rockchip

验证SoC的图显处理器及其他编解码模块时,可以基于libdrm modetest所提供的功能来丰富我们的verify条目。如单帧、多帧、旋转、缩放、裁剪等等。

modetest功能及流程

1

解析命令行参数

通过库函数getopt()处理modetest的命令行参数(图片可放大查看)

支持的命令行参数主要包括三类:

1) 查询类

2) 测试类

3) 通用选项

与解析命令函参数有关的三个API:

static int parse_connector(struct pipe_arg *pipe,const char *arg)static int parse_plane(struct plane_arg *plane,const char *p)static int parse_property(struct property_arg *p,const char *arg)staticvoidparse_fill_patterns(char *arg)

打开DRM设备

打开DRM设备的流程如下:

modetest只能打开static const char * const modules[]内定义的DRM驱动,默认支持的DRM驱动包括:

staticconst char *const modules[]={"i915","amdgpu","radeon","nouveau","vmwgfx","omapdrm","exynos","tilcdc","msm","sti","tegra","imx-drm","rockchip","atmel-hlcdc","fsl-dcu-drm","vc4","virtio_gpu","mediatek","meson","pl111","stm","sun4i-drm","armada-drm",};

当我们自己的图显驱动需要使用modetest进行验证的时候,需要在这里增加驱动名字。DRM驱动的名字定义在kernel driver的drm_driver数据结构中。

struct drm_driver {.../** @major: driver major number */
    int major;/** @minor: driver minor number */
    int minor;/** @patchlevel: driver patch level */
    int patchlevel;/** @name: driver name */
    char *name;/** @desc: driver description */
    char *desc;/** @date: driver date */
    char *date;...};

在打开设备的过程中,若通过-M参数指定了DRM驱动名,那么打开特定驱动;若未指定DRM驱动名,那么遍历modules[]中指定的DRM驱动。

另外,若没有指定-D参数(没有指定设备名),默认按照DRM驱动名打开DRM设备。这里面的-D参数是/dev/drixxx编号。例如-D 0,指定打开0号DRM设备。若指定了-D参数,那么首先按照-D指定设备编号来打开DRM设备。

获取设备资源

static struct resources *get_resources(struct device *dev){
…
    drmModeGetCrtc();drmModeGetEncoder();drmModeGetConnector();drmModeGetFB();drmModeGetPlane();
…
    drmModeObjectGetProperties(,,CRTC);drmModeObjectGetProperties(,,CONNECTOR);
…
}dump_resource(&dev, encoders);dump_resource(&dev, connectors);dump_resource(&dev, crtcs);dump_resource(&dev, planes);dump_resource(&dev, framebuffers);

配置property

若通过-w参数指定了property设置,那么执行

for(i =0; i < prop_count;++i)set_property(&dev,&prop_args[i]);

DRM配置

DRM的配置根据-a参数决定是否采用原子操作,当使用原子操作时原子更新属性,然后利用drmModeAtomicCommit()统一提交配置信息;否则,依次调用各个模块的配置API,如:set_mode()、set_planes()、set_cursors()、test_page_flip()等。

下面的内容是针对原子操作的。

模式配置

staticvoidatomic_set_mode(
    struct device *dev, 
    struct pipe_arg *pipes, 
    unsigned int count)

plane配置

这部分的代码应该是最精彩的部分,里面包括了生成待显示图像数据、配置gamma系数、内存数据填充、配置fb等。

支持4种图像格式,分别是:

enum util_fill_pattern {UTIL_PATTERN_TILES,UTIL_PATTERN_PLAIN,UTIL_PATTERN_SMPTE,UTIL_PATTERN_GRADIENT,};

plane配置的命令行参数是:

-P<plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]

进行plane配置之前首先按照上面的命令行参数逐项进行解析,最后一个format若不指定,默认使用XR24。

static int parse_plane(struct plane_arg *plane,const char *p){...
    plane->plane_id =strtoul(p,&end,10);...
    plane->crtc_id =strtoul(p,&end,10);...
    plane->w =strtoul(p,&end,10);...
    plane->h =strtoul(p,&end,10);if(*end =='+'||*end =='-'){
        plane->x =strtol(end,&end,10);...
        plane->y =strtol(end,&end,10);...}...if(*end =='@'){strncpy(plane->format_str, end +1,4);
        plane->format_str[4]='\0';}else{strcpy(plane->format_str,"XR24");}

    plane->fourcc =util_format_fourcc(plane->format_str);...}

关于plane显示功能的配置包括三部分:

1) part 1 申请内存空间

user space的程序发起ioctl请求,kernel driver完成内存空间的分配

2) part 2 填充图显数据

根据format格式向申请的内存空间填充rgb或yuv格式的图显数据

3) part 3 framebuffer绑定

创建一个framebuffer-DMA空间,将已准备好的图显数据内存区域与framebuffer进行绑定。

上面的流程涉及到了3个ioctl命令码,如下:

vsync

这个的本意是进行刷新率的测试,但是可以基于这个做简单的2D多帧测试,就不用引入其他视频测试工具如mplayer。

原子操作统一提交commit

配置结束后统一结交给DRM驱动的ioctl API

/* user space API */drmModeAtomicCommit(
    dev.fd, 
    dev.req,DRM_MODE_ATOMIC_ALLOW_MODESET,NULL);/* kernel DRM driver
 * drivers/gpu/drm/drm_atomic_uapi.c
 */drm_mode_atomic_ioctl(struct drm_device *dev,void*data, 
    struct drm_file *file_priv){
…
}

kernel DRM driver ioctl

提供的ioctl API函数定义在1) drivers/gpu/drm/drm_atomic_uapi.c2) drivers/gpu/drm/drm_ioctl.c3) drivers/gpu/drm/drm_auth.c

IOCTL COMMAND码定义在

1) include/uapi/drm/drm.h

假如依赖原子操作,那么modetest图形显示参数配置调用了

DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic);

在kernel驱动中对应drm_ioctl.c中定义:

DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl

而drm_mode_atomic_ioctl代码实现在drm_atomic_uapi.c中

int drm_mode_atomic_ioctl(struct drm_device *dev,void*data, struct drm_file *file_priv){
    struct drm_mode_atomic *arg = data;...
    unsigned int copied_objs, copied_props;
    struct drm_atomic_state *state;
    struct drm_modeset_acquire_ctx ctx;
    struct drm_out_fence_state *fence_state;
    int ret =0;
    unsigned int i, j, num_fences;
…
}

原子提交的用户空间代码与内核空间代码的交互流程如下:

modetest验证

2

虚拟机版本:

ubuntu版本:

libdrm代码版本:

ubuntu虚拟机需要切换到命令行模式,否则界面模式下会占用dri设备导致modetest无法正常执行。

进入命令行模式方法:

ctrl+alt+f1

退出命令行模式方法:

ctrl+alt+f7

切换到命令行模式下执行modetest

单帧验证:

./modetest -M vmwgfx -D0-a -s 34@36:1280x960  -P32@36:1280x960 -Ftiles

结果

多帧验证:

借助vsync这个选项修改代码,轮询显示modetest支持的4种图像格式来实现多个图像的输出

修改的代码如下:

命令行:

./modetest -M vmwgfx -D0-a -s 34@36:1280x960  -P32@36:1280x960 -v -Ftiles

限于篇幅没能把libdrm的功能完全的呈现出来,关于图显系统的验证还有很多的方法,这里只是冰山的一角。欢迎补充交流。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值