内容和参考

文章内容

libdrm得使用-1 知道如何使用modetest来出图,
本文分析下用户层开发代码 以及modetest源码分析;

相关参考

应用层代码

其实这些代码,何小龙-DRM系列应用开发 1-8 已经讲的非常详细,按照过程自己操作遍即可
这些代码指导我们应用是如何调用:libdrm.so 得, 但我们本章不分析具体内容,先记录下如何使用,后续会详细分析;
image.png

基础操作代码:

  1. #define _GNU_SOURCE
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <stdbool.h>
  5. #include <stdint.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/mman.h>
  10. #include <time.h>
  11. #include <unistd.h>
  12. #include <xf86drm.h>
  13. #include <xf86drmMode.h>
  14. int main(int argc, char **argv)
  15. {
  16. /* open the drm device */
  17. open("/dev/dri/card0");
  18. /* get crtc/encoder/connector id */
  19. drmModeGetResources(...);
  20. /* get connector for display mode */
  21. drmModeGetConnector(...);
  22. /* create a dumb-buffer */
  23. drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB);
  24. /* bind the dumb-buffer to an FB object */
  25. drmModeAddFB(...);
  26. /* map the dumb buffer for userspace drawing */
  27. drmIoctl(DRM_IOCTL_MODE_MAP_DUMB);
  28. mmap(...);
  29. /* start display */
  30. int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
  31. uint32_t x, uint32_t y, uint32_t *connectors, int count,
  32. drmModeModeInfoPtr mode);
  33. }

modetest代码

2.libdrm的使用-2 - 图2

资源得获取(重点)

prop相关

  1. // properties 相关结构体
  2. struct plane/crtc/connector {
  3. ......
  4. // 属性域 drmModeObjectGetProperties
  5. drmModeObjectProperties *props;
  6. // 值域 drmModeGetProperty
  7. drmModePropertyRes **props_info;
  8. };
  9. typedef struct _drmModeObjectProperties {
  10. uint32_t count_props; // prop得个数
  11. uint32_t *props; //
  12. uint64_t *prop_values;
  13. } drmModeObjectProperties, *drmModeObjectPropertiesPtr;
  14. typedef struct _drmModeProperty {
  15. uint32_t prop_id;
  16. uint32_t flags;
  17. char name[DRM_PROP_NAME_LEN];
  18. int count_values;
  19. uint64_t *values; /* store the blob lengths */
  20. int count_enums;
  21. struct drm_mode_property_enum *enums;
  22. int count_blobs;
  23. uint32_t *blob_ids; /* store the blob IDs */
  24. } drmModePropertyRes, *drmModePropertyPtr;
  25. get_properties(_res, type, Type)
  26. drmModeObjectGetProperties
  27. DRM_IOCTL_MODE_OBJ_GETPROPERTIES => drm_mode_obj_get_properties_ioctl
  28. => 获取所有属性
  29. drmModeGetProperty
  30. DRM_IOCTL_MODE_GETPROPERTY => drm_mode_getproperty_ioctl
  31. => 获取属性得详细信息
  32. dump_prop 打印属性信息
  33. prop:
  34. id name:
  35. flags: flags type
  36. value infomation

plane资源

  1. root@inno-MS-7B89:busybox# modetest -p
  2. Planes:
  3. id crtc fb CRTC x,y x,y gamma size possible crtcs
  4. 41 51 97 0,0 0,0 0 0x00000001
  5. formats: C8 YUYV UYVY XR24 AR24 RG16 XR15 AR15 XB30 AB30 XB24 AB24 XR30 AR30 XB4H AB4H
  6. props:
  7. 8 type:
  8. flags: immutable enum
  9. enums: Overlay=0 Primary=1 Cursor=2
  10. value: 1
  11. 42 zpos:
  12. flags: range
  13. values: 0 254
  14. value: 0
  15. 43 alpha:
  16. flags: range
  17. values: 0 65535
  18. value: 65535
  19. 44 pixel blend mode:
  20. flags: enum
  21. enums: None=2 Pre-multiplied=0 Coverage=1
  22. value: 0
  23. ......

代码分析 modetest.c中

  1. drmModeGetPlaneResources(dev->fd) // 获取资源总数
  2. DRM_IOCTL_MODE_GETPLANERESOURCES => drm_mode_getplane_res => mode_config.plane_list
  3. drmModeGetPlane // 对每一个资源,获取详细信息
  4. DRM_IOCTL_MODE_GETPLANE => drm_mode_getplane => mode_config.plane_list 来获取某一个plane
  5. => copy_to_user 来获取所支持得formats
  6. drmModeObjectGetProperties
  7. DRM_IOCTL_MODE_OBJ_GETPROPERTIES => drm_mode_obj_get_properties_ioctl
  8. => 获取所有属性
  9. drmModeGetProperty
  10. DRM_IOCTL_MODE_GETPROPERTY => drm_mode_getproperty_ioctl
  11. => 获取属性得详细值
  12. dump_planes
  13. printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");
  14. 打印 drm_mode_getplane 获取到的 plane信息及 formats
  15. prop:
  16. id name:
  17. flags: flags type
  18. value infomation

非atomic模式

检测 crtc 和 plane得链接

  1. if (set_preferred || count || plane_count){...} // -s 或者 -P 或者 -r 至少配置一个
  2. // -r set_preferred 设置首选得链接器模式
  3. // -P 设置plane和crtc得链接
  4. // -s 设置crtc和connector得链接

检测支持dumb接口

在自己驱动得 struct drm_driver 中必须支持 dumb_create 接口
.dumb_create = (dumb_create_func),

  1. ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);

使用-s输出

我们在验证一个平台输出时,最简单得方式是: modetest - M xxx -s connector_id@crtc_id:WxH@XR24 ,所以这里先看 -s 得分支

每一个 -s 参数都会影响 modetest里边得 count++;

参数解析

  1. struct pipe_arg {
  2. const char **cons; // num_cons得数组,存放char*, 其实是args得 connecot_id 得字符串拷贝
  3. uint32_t *con_ids; // num_cons得数组,存放connector_id , pipe_resolve_connectors 中初始化
  4. unsigned int num_cons; // <connector_id>[,<connector_id>] 得个数
  5. uint32_t crtc_id; // @<crtc_id> ,获取crtc_id : strtoul(arg, &endp, 10);
  6. char mode_str[64]; // <mode>
  7. char format_str[5]; // [@<format>]
  8. float vrefresh;
  9. unsigned int fourcc;
  10. drmModeModeInfo *mode;
  11. struct crtc *crtc;
  12. unsigned int fb_id[2], current_fb_id;
  13. struct timeval start;
  14. int swap_count;
  15. };
  16. parse_connector
  17. -s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>] set a mode
  18. // 1. 先根据 <connector_id>[,<connector_id>] 来获取 conector得个数: pipe->num_cons , 并分配相关参数内存
  19. pipe->num_cons=1;
  20. for (p = arg; *p && *p != ':' && *p != '@'; ++p) {
  21. if (*p == ',')
  22. pipe->num_cons++;
  23. }
  24. pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids));
  25. pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons));
  26. // 2. 拷贝args得id字符串到pipe->cons[i]
  27. pipe->cons[i] = strndup(p, endp - p);
  28. // 3. 获取crtc得id
  29. pipe->crtc_id=strtoul(arg, &endp, 10);
  30. // 4. 获取mode
  31. strncpy(pipe->mode_str, arg, len);
  32. // 5. 获取格式信息
  33. strncpy(pipe->format_str, p + 1, 4); // 格式得字符串
  34. pipe->fourcc = util_format_fourcc(pipe->format_str); // 格式字符串对应得format id

其实,显示得模式 和何小龙得代码:最简单的DRM应用程序 (page-flip) 一致,流程类似

  1. set_mode(&dev, pipe_args, count); // pipe_args 是参数得结构, count 是 -s得个数
  2. pipe_resolve_connectors // 根据pipe_args中得id获取connector
  3. get_connector_by_name
  4. pipe->con_ids[i] = id; 根据con 参数 检测资源表 get_connector_by_name 中得connector,并获取id
  5. connector_find_mode // 检测 pipe->mode_str得模式,在connector->count_modes 中是否支持该模式, 也就是分辨率等信息
  6. // drm得modeset操作,和何小龙得流程一致, 这几部分后期怎么实现,参考后边得驱动部分:
  7. bo_fb_create(); // modeset_create_fb 创建frame buffer
  8. bo_create_dumb // DRM_IOCTL_MODE_CREATE_DUMB
  9. bo_map(bo, &virtual); // 这个virtual 指向得地址,就是mmap获取到得虚拟地址
  10. drmIoctl(bo->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
  11. drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
  12. bo->fd, arg.offset);
  13. util_fill_pattern // 给buffer填充数据
  14. bo_unmap(bo);
  15. drmModeSetCrtc(); // DRM_IOCTL_MODE_SETCRTC
  16. drmModeDirtyFB(); // DRM_IOCTL_MODE_DIRTYFB
  17. set_gamma(); // DRM_IOCTL_MODE_SETGAMMA, skip,暂时不用看,
  18. clear_mode(&dev);

附加属性-w

内核在支持 属性-对象 得配置以后,modetest 给用户提供了 配置 每个对象得属性值得接口,就是 -w
每一个 -w 参数都会影响 modetest里边得 _prop_count++;_

参数解析

  1. parse_property(&prop_args[prop_count], optarg);
  2. struct property_arg {
  3. uint32_t obj_id; // object_id
  4. uint32_t obj_type;
  5. char name[DRM_PROP_NAME_LEN+1]; // prop_name
  6. uint32_t prop_id;
  7. uint64_t value; // prop value
  8. bool optional;
  9. };

设置参数
设置参数得流程很简单: 从资源表查找obj -> 从obj查找属性对应id -> drmModeObjectSetProperty / drmModeAtomicAddProperty 设置属性值

  1. for (i = 0; i < prop_count; ++i)
  2. set_property(&dev, &prop_args[i]);
  3. // 在资源表中查找 crtc, connector, plane,直到能找到匹配当前prop_args->obj_id 得对象
  4. find_object(dev->resources, crtc, CRTC);
  5. find_object(dev->resources, connector, CONNECTOR);
  6. find_object(dev->resources, plane, PLANE);
  7. // 设置属性
  8. drmModeObjectSetProperty // DRM_IOCTL_MODE_OBJ_SETPROPERTY 驱动:
  9. or
  10. drmModeAtomicAddProperty // atomic:

atomic模式

image.png