内容和参考
文章内容
从 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 {......// 属性域 drmModeObjectGetPropertiesdrmModeObjectProperties *props;// 值域 drmModeGetPropertydrmModePropertyRes **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)drmModeObjectGetPropertiesDRM_IOCTL_MODE_OBJ_GETPROPERTIES => drm_mode_obj_get_properties_ioctl=> 获取所有属性drmModeGetPropertyDRM_IOCTL_MODE_GETPROPERTY => drm_mode_getproperty_ioctl=> 获取属性得详细信息dump_prop 打印属性信息prop:id name:flags: flags typevalue infomation
plane资源
root@inno-MS-7B89:busybox# modetest -pPlanes:id crtc fb CRTC x,y x,y gamma size possible crtcs41 51 97 0,0 0,0 0 0x00000001formats: C8 YUYV UYVY XR24 AR24 RG16 XR15 AR15 XB30 AB30 XB24 AB24 XR30 AR30 XB4H AB4Hprops:8 type:flags: immutable enumenums: Overlay=0 Primary=1 Cursor=2value: 142 zpos:flags: rangevalues: 0 254value: 043 alpha:flags: rangevalues: 0 65535value: 6553544 pixel blend mode:flags: enumenums: None=2 Pre-multiplied=0 Coverage=1value: 0......
代码分析 modetest.c中
drmModeGetPlaneResources(dev->fd) // 获取资源总数DRM_IOCTL_MODE_GETPLANERESOURCES => drm_mode_getplane_res => mode_config.plane_listdrmModeGetPlane // 对每一个资源,获取详细信息DRM_IOCTL_MODE_GETPLANE => drm_mode_getplane => mode_config.plane_list 来获取某一个plane=> copy_to_user 来获取所支持得formatsdrmModeObjectGetPropertiesDRM_IOCTL_MODE_OBJ_GETPROPERTIES => drm_mode_obj_get_properties_ioctl=> 获取所有属性drmModeGetPropertyDRM_IOCTL_MODE_GETPROPERTY => drm_mode_getproperty_ioctl=> 获取属性得详细值dump_planesprintf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");打印 drm_mode_getplane 获取到的 plane信息及 formatsprop:id name:flags: flags typevalue 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得idpipe->crtc_id=strtoul(arg, &endp, 10);// 4. 获取modestrncpy(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获取connectorget_connector_by_namepipe->con_ids[i] = id; 根据con 参数 检测资源表 get_connector_by_name 中得connector,并获取idconnector_find_mode // 检测 pipe->mode_str得模式,在connector->count_modes 中是否支持该模式, 也就是分辨率等信息// drm得modeset操作,和何小龙得流程一致, 这几部分后期怎么实现,参考后边得驱动部分:bo_fb_create(); // modeset_create_fb 创建frame bufferbo_create_dumb // DRM_IOCTL_MODE_CREATE_DUMBbo_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_SETCRTCdrmModeDirtyFB(); // DRM_IOCTL_MODE_DIRTYFBset_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_iduint32_t obj_type;char name[DRM_PROP_NAME_LEN+1]; // prop_nameuint32_t prop_id;uint64_t value; // prop valuebool 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 驱动:ordrmModeAtomicAddProperty // atomic:
atomic模式

