内容和参考
文章内容
从 libdrm得使用-1 知道如何使用modetest来出图,
本文分析下用户层开发代码 以及modetest源码分析;
相关参考
- 何小龙-DRM 系列应用开发 1-8
应用层代码
其实这些代码,何小龙-DRM系列应用开发 1-8 已经讲的非常详细,按照过程自己操作遍即可
这些代码指导我们应用是如何调用:libdrm.so 得, 但我们本章不分析具体内容,先记录下如何使用,后续会详细分析;
基础操作代码:
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
int main(int argc, char **argv)
{
/* open the drm device */
open("/dev/dri/card0");
/* get crtc/encoder/connector id */
drmModeGetResources(...);
/* get connector for display mode */
drmModeGetConnector(...);
/* create a dumb-buffer */
drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB);
/* bind the dumb-buffer to an FB object */
drmModeAddFB(...);
/* map the dumb buffer for userspace drawing */
drmIoctl(DRM_IOCTL_MODE_MAP_DUMB);
mmap(...);
/* start display */
int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
uint32_t x, uint32_t y, uint32_t *connectors, int count,
drmModeModeInfoPtr mode);
}
modetest代码
资源得获取(重点)
prop相关
// properties 相关结构体
struct plane/crtc/connector {
......
// 属性域 drmModeObjectGetProperties
drmModeObjectProperties *props;
// 值域 drmModeGetProperty
drmModePropertyRes **props_info;
};
typedef struct _drmModeObjectProperties {
uint32_t count_props; // prop得个数
uint32_t *props; //
uint64_t *prop_values;
} drmModeObjectProperties, *drmModeObjectPropertiesPtr;
typedef struct _drmModeProperty {
uint32_t prop_id;
uint32_t flags;
char name[DRM_PROP_NAME_LEN];
int count_values;
uint64_t *values; /* store the blob lengths */
int count_enums;
struct drm_mode_property_enum *enums;
int count_blobs;
uint32_t *blob_ids; /* store the blob IDs */
} drmModePropertyRes, *drmModePropertyPtr;
get_properties(_res, type, Type)
drmModeObjectGetProperties
DRM_IOCTL_MODE_OBJ_GETPROPERTIES => drm_mode_obj_get_properties_ioctl
=> 获取所有属性
drmModeGetProperty
DRM_IOCTL_MODE_GETPROPERTY => drm_mode_getproperty_ioctl
=> 获取属性得详细信息
dump_prop 打印属性信息
prop:
id name:
flags: flags type
value infomation
plane资源
root@inno-MS-7B89:busybox# modetest -p
Planes:
id crtc fb CRTC x,y x,y gamma size possible crtcs
41 51 97 0,0 0,0 0 0x00000001
formats: C8 YUYV UYVY XR24 AR24 RG16 XR15 AR15 XB30 AB30 XB24 AB24 XR30 AR30 XB4H AB4H
props:
8 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 1
42 zpos:
flags: range
values: 0 254
value: 0
43 alpha:
flags: range
values: 0 65535
value: 65535
44 pixel blend mode:
flags: enum
enums: None=2 Pre-multiplied=0 Coverage=1
value: 0
......
代码分析 modetest.c中
drmModeGetPlaneResources(dev->fd) // 获取资源总数
DRM_IOCTL_MODE_GETPLANERESOURCES => drm_mode_getplane_res => mode_config.plane_list
drmModeGetPlane // 对每一个资源,获取详细信息
DRM_IOCTL_MODE_GETPLANE => drm_mode_getplane => mode_config.plane_list 来获取某一个plane
=> copy_to_user 来获取所支持得formats
drmModeObjectGetProperties
DRM_IOCTL_MODE_OBJ_GETPROPERTIES => drm_mode_obj_get_properties_ioctl
=> 获取所有属性
drmModeGetProperty
DRM_IOCTL_MODE_GETPROPERTY => drm_mode_getproperty_ioctl
=> 获取属性得详细值
dump_planes
printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");
打印 drm_mode_getplane 获取到的 plane信息及 formats
prop:
id name:
flags: flags type
value infomation
非atomic模式
检测 crtc 和 plane得链接
if (set_preferred || count || plane_count){...} // -s 或者 -P 或者 -r 至少配置一个
// -r set_preferred 设置首选得链接器模式
// -P 设置plane和crtc得链接
// -s 设置crtc和connector得链接
检测支持dumb接口
在自己驱动得 struct drm_driver 中必须支持 dumb_create 接口
.dumb_create = (dumb_create_func),
ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
使用-s输出
我们在验证一个平台输出时,最简单得方式是: modetest - M xxx -s connector_id@crtc_id:WxH@XR24 ,所以这里先看 -s 得分支
每一个 -s 参数都会影响 modetest里边得 count++;
参数解析
struct pipe_arg {
const char **cons; // num_cons得数组,存放char*, 其实是args得 connecot_id 得字符串拷贝
uint32_t *con_ids; // num_cons得数组,存放connector_id , pipe_resolve_connectors 中初始化
unsigned int num_cons; // <connector_id>[,<connector_id>] 得个数
uint32_t crtc_id; // @<crtc_id> ,获取crtc_id : strtoul(arg, &endp, 10);
char mode_str[64]; // <mode>
char format_str[5]; // [@<format>]
float vrefresh;
unsigned int fourcc;
drmModeModeInfo *mode;
struct crtc *crtc;
unsigned int fb_id[2], current_fb_id;
struct timeval start;
int swap_count;
};
parse_connector
-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>] set a mode
// 1. 先根据 <connector_id>[,<connector_id>] 来获取 conector得个数: pipe->num_cons , 并分配相关参数内存
pipe->num_cons=1;
for (p = arg; *p && *p != ':' && *p != '@'; ++p) {
if (*p == ',')
pipe->num_cons++;
}
pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids));
pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons));
// 2. 拷贝args得id字符串到pipe->cons[i]
pipe->cons[i] = strndup(p, endp - p);
// 3. 获取crtc得id
pipe->crtc_id=strtoul(arg, &endp, 10);
// 4. 获取mode
strncpy(pipe->mode_str, arg, len);
// 5. 获取格式信息
strncpy(pipe->format_str, p + 1, 4); // 格式得字符串
pipe->fourcc = util_format_fourcc(pipe->format_str); // 格式字符串对应得format id
其实,显示得模式 和何小龙得代码:最简单的DRM应用程序 (page-flip) 一致,流程类似
set_mode(&dev, pipe_args, count); // pipe_args 是参数得结构, count 是 -s得个数
pipe_resolve_connectors // 根据pipe_args中得id获取connector
get_connector_by_name
pipe->con_ids[i] = id; 根据con 参数 检测资源表 get_connector_by_name 中得connector,并获取id
connector_find_mode // 检测 pipe->mode_str得模式,在connector->count_modes 中是否支持该模式, 也就是分辨率等信息
// drm得modeset操作,和何小龙得流程一致, 这几部分后期怎么实现,参考后边得驱动部分:
bo_fb_create(); // modeset_create_fb 创建frame buffer
bo_create_dumb // DRM_IOCTL_MODE_CREATE_DUMB
bo_map(bo, &virtual); // 这个virtual 指向得地址,就是mmap获取到得虚拟地址
drmIoctl(bo->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
bo->fd, arg.offset);
util_fill_pattern // 给buffer填充数据
bo_unmap(bo);
drmModeSetCrtc(); // DRM_IOCTL_MODE_SETCRTC
drmModeDirtyFB(); // DRM_IOCTL_MODE_DIRTYFB
set_gamma(); // DRM_IOCTL_MODE_SETGAMMA, skip,暂时不用看,
clear_mode(&dev);
附加属性-w
内核在支持 属性-对象 得配置以后,modetest 给用户提供了 配置 每个对象得属性值得接口,就是 -w
每一个 -w 参数都会影响 modetest里边得 _prop_count++;_
参数解析
parse_property(&prop_args[prop_count], optarg);
struct property_arg {
uint32_t obj_id; // object_id
uint32_t obj_type;
char name[DRM_PROP_NAME_LEN+1]; // prop_name
uint32_t prop_id;
uint64_t value; // prop value
bool optional;
};
设置参数
设置参数得流程很简单: 从资源表查找obj -> 从obj查找属性对应id -> drmModeObjectSetProperty / drmModeAtomicAddProperty 设置属性值
for (i = 0; i < prop_count; ++i)
set_property(&dev, &prop_args[i]);
// 在资源表中查找 crtc, connector, plane,直到能找到匹配当前prop_args->obj_id 得对象
find_object(dev->resources, crtc, CRTC);
find_object(dev->resources, connector, CONNECTOR);
find_object(dev->resources, plane, PLANE);
// 设置属性
drmModeObjectSetProperty // DRM_IOCTL_MODE_OBJ_SETPROPERTY 驱动:
or
drmModeAtomicAddProperty // atomic: