• Linux内核4.14版本——drm框架分析(11)——DRM_IOCTL_MODE_ADDFB2(drm_mode_addfb2)


    目录

    1. drm_mode_addfb2

    2. drm_internal_framebuffer_create

    3. drm_fb_cma_create->drm_gem_fb_create->drm_gem_fb_create_with_funcs

    4. drm_gem_fb_alloc

     4.1 drm_helper_mode_fill_fb_struct

    4.2 drm_framebuffer_init

    5. 调用流程图


            书接上回,使用drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)接口创建了一块内存放在了gem cma的对象里。

            gem obj创建之后需要与一块drm_framebuffer进行绑定使用,因为最终刷图使用的是fb。使用下面接口会创建drm_framebuffer并与上节创建的gem obj进行绑定。

            目前使用较多的就是drm_mode_addfb2接口,该接口完成了下面的功能。

    1. drm_mode_addfb2

    1. int drm_mode_addfb2(struct drm_device *dev,
    2. void *data, struct drm_file *file_priv)
    3. {
    4. struct drm_mode_fb_cmd2 *r = data;
    5. struct drm_framebuffer *fb;
    6. if (!drm_core_check_feature(dev, DRIVER_MODESET))
    7. return -EINVAL;
    8. fb = drm_internal_framebuffer_create(dev, r, file_priv);
    9. if (IS_ERR(fb))
    10. return PTR_ERR(fb);
    11. DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
    12. r->fb_id = fb->base.id;
    13. /* Transfer ownership to the filp for reaping on close */
    14. mutex_lock(&file_priv->fbs_lock);
    15. list_add(&fb->filp_head, &file_priv->fbs);
    16. mutex_unlock(&file_priv->fbs_lock);
    17. return 0;
    18. }

           drm_mode_addfb2主要做了三件大事:

            (1)调用drm_internal_framebuffer_create创建一个drm_framebuffer。

            (2)把drm_framebuffer的struct drm_mode_object的ID返回给应用。

            (3)加到file_priv的fbs链表中。

    下面我们看一下函数drm_internal_framebuffer_create。

    2. drm_internal_framebuffer_create

    1. struct drm_framebuffer *
    2. drm_internal_framebuffer_create(struct drm_device *dev,
    3. const struct drm_mode_fb_cmd2 *r,
    4. struct drm_file *file_priv)
    5. {
    6. ........
    7. fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
    8. if (IS_ERR(fb)) {
    9. DRM_DEBUG_KMS("could not create framebuffer\n");
    10. return fb;
    11. }
    12. return fb;
    13. }

            检查参数,然后调用dev->mode_config.funcs->fb_create(dev, file_priv, r),可以自己实现,也可以使用内核现成的drm_fb_cma_create。

    3. drm_fb_cma_create->drm_gem_fb_create->drm_gem_fb_create_with_funcs

    1. struct drm_framebuffer *
    2. drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
    3. const struct drm_mode_fb_cmd2 *mode_cmd,
    4. const struct drm_framebuffer_funcs *funcs)
    5. {
    6. const struct drm_format_info *info;
    7. struct drm_gem_object *objs[4];
    8. struct drm_framebuffer *fb;
    9. int ret, i;
    10. info = drm_get_format_info(dev, mode_cmd);
    11. if (!info)
    12. return ERR_PTR(-EINVAL);
    13. for (i = 0; i < info->num_planes; i++) {
    14. unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
    15. unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
    16. unsigned int min_size;
    17. objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
    18. if (!objs[i]) {
    19. DRM_DEV_ERROR(dev->dev, "Failed to lookup GEM\n");
    20. ret = -ENOENT;
    21. goto err_gem_object_put;
    22. }
    23. min_size = (height - 1) * mode_cmd->pitches[i]
    24. + width * info->cpp[i]
    25. + mode_cmd->offsets[i];
    26. if (objs[i]->size < min_size) {
    27. // DRM_DEV_ERROR(dev->dev, "objs %d Size(%d %d) error\n",
    28. // i, objs[i]->size, min_size);
    29. drm_gem_object_put_unlocked(objs[i]);
    30. ret = -EINVAL;
    31. goto err_gem_object_put;
    32. }
    33. }
    34. fb = drm_gem_fb_alloc(dev, mode_cmd, objs, i, funcs);
    35. if (IS_ERR(fb)) {
    36. ret = PTR_ERR(fb);
    37. DRM_DEV_ERROR(dev->dev, "alloc error %d\n", ret);
    38. goto err_gem_object_put;
    39. }
    40. return fb;
    41. err_gem_object_put:
    42. for (i--; i >= 0; i--)
    43. drm_gem_object_put_unlocked(objs[i]);
    44. return ERR_PTR(ret);
    45. }

            (1)通过应用提供的handle,使用drm_gem_object_lookup找到上次创建的gem obj。

            (2)调用drm_gem_fb_alloc,分配一个drm_framebuffer,将gem obj赋值给framebuffer中的obj。

    4. drm_gem_fb_alloc

    1. static struct drm_framebuffer *
    2. drm_gem_fb_alloc(struct drm_device *dev,
    3. const struct drm_mode_fb_cmd2 *mode_cmd,
    4. struct drm_gem_object **obj, unsigned int num_planes,
    5. const struct drm_framebuffer_funcs *funcs)
    6. {
    7. struct drm_framebuffer *fb;
    8. int ret, i;
    9. fb = kzalloc(sizeof(*fb), GFP_KERNEL);
    10. if (!fb)
    11. return ERR_PTR(-ENOMEM);
    12. drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
    13. for (i = 0; i < num_planes; i++)
    14. fb->obj[i] = obj[i];
    15. ret = drm_framebuffer_init(dev, fb, funcs);
    16. if (ret) {
    17. DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n",
    18. ret);
    19. kfree(fb);
    20. return ERR_PTR(ret);
    21. }
    22. return fb;
    23. }

     4.1 drm_helper_mode_fill_fb_struct

    1. void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
    2. struct drm_framebuffer *fb,
    3. const struct drm_mode_fb_cmd2 *mode_cmd)
    4. {
    5. int i;
    6. fb->dev = dev;
    7. fb->format = drm_get_format_info(dev, mode_cmd);
    8. fb->width = mode_cmd->width;
    9. fb->height = mode_cmd->height;
    10. for (i = 0; i < 4; i++) {
    11. fb->pitches[i] = mode_cmd->pitches[i];
    12. fb->offsets[i] = mode_cmd->offsets[i];
    13. }
    14. fb->modifier = mode_cmd->modifier[0];
    15. fb->flags = mode_cmd->flags;
    16. }

          将应用传入的长,宽,format,pitch,flag等填充framebuffer结构体。

    4.2 drm_framebuffer_init

    1. int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
    2. const struct drm_framebuffer_funcs *funcs)
    3. {
    4. int ret;
    5. if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
    6. return -EINVAL;
    7. INIT_LIST_HEAD(&fb->filp_head);
    8. fb->funcs = funcs;
    9. ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
    10. false, drm_framebuffer_free);
    11. if (ret)
    12. goto out;
    13. mutex_lock(&dev->mode_config.fb_lock);
    14. dev->mode_config.num_fb++;
    15. list_add(&fb->head, &dev->mode_config.fb_list);
    16. mutex_unlock(&dev->mode_config.fb_lock);
    17. drm_mode_object_register(dev, &fb->base);
    18. out:
    19. return ret;
    20. }

            相关字段填充完成后会将fb添加进dev->mode_config.fb_list便于后面使用的时候通过id进行查找, drm的组件都是通过dev->mode_config中的链表进行管理的,只要拿到mode_config就可以拿到drm相关信息。

            至此drm_framebuffer已经创建完毕。通过r->fb_id = fb->base.id;将fb_id返回给用户。

    5. 调用流程图

  • 相关阅读:
    从编译内核、制作initramfs到使用QEMU运行内核
    leetcode/含有所有字符的最短字符串
    【目标检测】数据增强:YOLO官方数据增强实现/imgaug的简单使用
    【开源】在线考试系统 JAVA+Vue.js+SpringBoot 新手入门项目
    mysql报错:Duplicate entry ‘...‘ for key ‘field‘
    C/C++常用关键字详解
    idea创建纯净的maven项目简单的maven工程
    【考研数学】一. 极限与导数
    确保软件供应链安全,不容忽略的三大步骤
    极简idea下git操作(二)
  • 原文地址:https://blog.csdn.net/yangguoyu8023/article/details/129249184