linux平台普遍采用的DRM软件架构中,不仅包含了内核空间驱动层的代码,而且提供应用层的支撑库libdrm。libdrm基于DRI协议通过ioctl与2D图显驱动进行交互,配置图显处理器以及HDMI、MIPI、LVDS等编解码单元。
from rockchip
验证SoC的图显处理器及其他编解码模块时,可以基于libdrm modetest所提供的功能来丰富我们的verify条目。如单帧、多帧、旋转、缩放、裁剪等等。
modetest功能及流程
1
解析命令行参数
通过库函数getopt()处理modetest的命令行参数(图片可放大查看)。
支持的命令行参数主要包括三类:
1) 查询类
2) 测试类
3) 通用选项
与解析命令函参数有关的三个API:
代码语言:javascript复制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)
static void parse_fill_patterns(char *arg)
打开DRM设备
打开DRM设备的流程如下:
modetest只能打开static const char * const modules[]内定义的DRM驱动,默认支持的DRM驱动包括:
代码语言:javascript复制static const 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数据结构中。
代码语言:javascript复制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设备。
获取设备资源
代码语言:javascript复制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设置,那么执行
代码语言:javascript复制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()等。
下面的内容是针对原子操作的。
模式配置
代码语言:javascript复制static void atomic_set_mode(
struct device *dev,
struct pipe_arg *pipes,
unsigned int count)
plane配置
这部分的代码应该是最精彩的部分,里面包括了生成待显示图像数据、配置gamma系数、内存数据填充、配置fb等。
支持4种图像格式,分别是:
代码语言:javascript复制enum util_fill_pattern {
UTIL_PATTERN_TILES,
UTIL_PATTERN_PLAIN,
UTIL_PATTERN_SMPTE,
UTIL_PATTERN_GRADIENT,
};
plane配置的命令行参数是:
代码语言:javascript复制-P <plane_id>@<crtc_id>:<w>x<h>[ <x> <y>][*<scale>][@<format>]
进行plane配置之前首先按照上面的命令行参数逐项进行解析,最后一个format若不指定,默认使用XR24。
代码语言:javascript复制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] = '