• Linux内核4.14版本——drm框架分析(14)——Atomic KMS 架构(struct drm_atomic_state)


     目录

    1. drm_atomic_state_alloc创建drm_atomic_state

    1.1 drm_atomic_state_init

    2. 各个drm object对应的state

    2.1 drm_atomic_get_crtc_state

    2.2 drm_atomic_get_plane_state

    2.3 drm_atomic_get_connector_state

    2.4 struct __drm_{object}_state


         我们从前面两篇文章可以看到,无论是drm_mode_setcrtc和drm_mode_setplane最终都会调用drm_atomic_commit,其参数为struct drm_atomic_state。我们来分析一下。

           Atomic Mode Setting(后续简称A-KMS)。该架构会弥补之前API的不足,由于原先的API不支持同时更新整个DRM显示pipeline的状态,因此KMS过程中会出现一些中间状态,容易造成开发者不希望看见的结果,影响用户体验。同时,原先的KMS接口也不支持回滚,需要应用程序自己记录原先的配置状态,Atomic Mode Setting也解决了这个问题。

            Atomic commit 表示:本次 commit 操作,要么成功,要么保持原来的状态不变。即如果中途操作失败了,那些已经生效的配置需要恢复成之前的状态,就像没发生过 commit 操作似的。而Commit,则是因为本次操作可能会修改到多个参数,等修改好这些参数后,再一次性发起操作请求,有点类似与填表后“提交”材料的意思

            Atomic Mode Setting接口在用户态看来,是将原先各个KMS object的状态由隐式的通过API更新,变成了显式的对象属性。用户态程序可以通过通用的属性操作接口读写KMS object上的属性,更改不会立即生效,而是缓存起来。当应用程序更新完其所有想要更新的属性时,可以通过Commit操作告知要求KMS层真正的更新硬件的状态。此时驱动程序需要验证应用程序要求进行的修改是否合法,在合法的情况下,可以一次性完成整个显示状态的修改。A-KMS也实现了只用于检查新状态是否合法的接口。

           KMS框架提供了一套helper函数以帮助驱动程序作者实现原先的Legacy KMS接口,本质上,就是原先的legacy相关的接口都通过A-KMS兼容层实现的helper函数实现,实质上就是使用带有drm_atomic_helper前缀的helper函数实现原有的legacy接口。

            用户态相关接口:

    1. typedef struct _drmModeAtomicReq drmModeAtomicReq, *drmModeAtomicReqPtr;
    2. extern drmModeAtomicReqPtr drmModeAtomicAlloc(void);
    3. extern drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr req);
    4. extern int drmModeAtomicMerge(drmModeAtomicReqPtr base,
    5. drmModeAtomicReqPtr augment);
    6. extern void drmModeAtomicFree(drmModeAtomicReqPtr req);
    7. extern int drmModeAtomicGetCursor(drmModeAtomicReqPtr req);
    8. extern void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor);
    9. extern int drmModeAtomicAddProperty(drmModeAtomicReqPtr req,
    10. uint32_t object_id,
    11. uint32_t property_id,
    12. uint64_t value);
    13. extern int drmModeAtomicCommit(int fd,
    14. drmModeAtomicReqPtr req,
    15. uint32_t flags,
    16. void *user_data);

            用户态接口的本质就是扩展原有的属性接口,允许用户描述一个状态集合,然后通过drmModeAtomicCommit函数进行commit操做。从libdrm的代码中可以看到,commit的操作最后实质上调用了DRM_IOCTL_MODE_ATOMIC的ioctl,这就是Native接口唯一的入口。从内核代码中可以看到,该ioctl的处理函数为drm_mode_atomic_ioctl。以drm_mode_atomic_ioctl为线索,可以发现许多相关的实现。A-KMS的核心是整个显示控制器的状态集合,由一个独立的状态对象表示。一个DRM显示pipeline的整体状态由struct drm_atomic_state表示。

    1. struct drm_atomic_state {
    2. struct kref ref;
    3. struct drm_device *dev;
    4. bool allow_modeset : 1;
    5. bool legacy_cursor_update : 1;
    6. bool async_update : 1;
    7. struct __drm_planes_state *planes;
    8. struct __drm_crtcs_state *crtcs;
    9. int num_connector;
    10. struct __drm_connnectors_state *connectors;
    11. int num_private_objs;
    12. struct __drm_private_objs_state *private_objs;
    13. struct drm_modeset_acquire_ctx *acquire_ctx;
    14. struct work_struct commit_work;
    15. };

    drm_atomic_state和其他组件state的继承关系如下图:

    1. drm_atomic_state_alloc创建drm_atomic_state

    1. struct drm_atomic_state *
    2. drm_atomic_state_alloc(struct drm_device *dev)
    3. {
    4. struct drm_mode_config *config = &dev->mode_config;
    5. if (!config->funcs->atomic_state_alloc) {
    6. struct drm_atomic_state *state;
    7. state = kzalloc(sizeof(*state), GFP_KERNEL);
    8. if (!state)
    9. return NULL;
    10. if (drm_atomic_state_init(dev, state) < 0) {
    11. kfree(state);
    12. return NULL;
    13. }
    14. return state;
    15. }
    16. return config->funcs->atomic_state_alloc(dev);
    17. }

            函数中可以看到,drm_mode_config_funcs中提供了名为atomic_state_alloc的hook,允许我们自己实现state对象的创建。在默认情况下,函数会调用简单分配内存,然后使用drm_atomic_state_init进行初始化。

    1.1 drm_atomic_state_init

    1. int
    2. drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
    3. {
    4. kref_init(&state->ref);
    5. /* TODO legacy paths should maybe do a better job about
    6. * setting this appropriately?
    7. */
    8. state->allow_modeset = true;
    9. state->crtcs = kcalloc(dev->mode_config.num_crtc,
    10. sizeof(*state->crtcs), GFP_KERNEL);
    11. if (!state->crtcs)
    12. goto fail;
    13. state->planes = kcalloc(dev->mode_config.num_total_plane,
    14. sizeof(*state->planes), GFP_KERNEL);
    15. if (!state->planes)
    16. goto fail;
    17. state->dev = dev;
    18. DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state);
    19. return 0;
    20. fail:
    21. drm_atomic_state_default_release(state);
    22. return -ENOMEM;
    23. }

            初始化函数仅仅是简单分配分配drm_atomic_state中几个指针指向的内存区域。

    2. 各个drm object对应的state

    对于各个drm object对应的state,其创建操作由其对应的drm_{object}_funcs->atomic_duplicate_state实现,在驱动程序没有扩展drm_atomic_state的情况下,这个回调函数一般填写为drm_atomic_helper_{object}_duplicate_state。

    2.1 drm_atomic_get_crtc_state

    1. struct drm_crtc_state *
    2. drm_atomic_get_crtc_state(struct drm_atomic_state *state,
    3. struct drm_crtc *crtc)
    4. {
    5. int ret, index = drm_crtc_index(crtc);
    6. struct drm_crtc_state *crtc_state;
    7. WARN_ON(!state->acquire_ctx);
    8. crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
    9. if (crtc_state)
    10. return crtc_state;
    11. ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
    12. if (ret)
    13. return ERR_PTR(ret);
    14. crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
    15. if (!crtc_state)
    16. return ERR_PTR(-ENOMEM);
    17. state->crtcs[index].state = crtc_state;
    18. state->crtcs[index].old_state = crtc->state;
    19. state->crtcs[index].new_state = crtc_state;
    20. state->crtcs[index].ptr = crtc;
    21. crtc_state->state = state;
    22. DRM_DEBUG_ATOMIC("Added [CRTC:%d:%s] %p state to %p\n",
    23. crtc->base.id, crtc->name, crtc_state, state);
    24. return crtc_state;
    25. }

          drm_atomic_get_crtc_state--> crtc_state = crtc->funcs->atomic_duplicate_state(crtc);

    2.2 drm_atomic_get_plane_state

    1. struct drm_plane_state *
    2. drm_atomic_get_plane_state(struct drm_atomic_state *state,
    3. struct drm_plane *plane)
    4. {
    5. int ret, index = drm_plane_index(plane);
    6. struct drm_plane_state *plane_state;
    7. WARN_ON(!state->acquire_ctx);
    8. plane_state = drm_atomic_get_existing_plane_state(state, plane);
    9. if (plane_state)
    10. return plane_state;
    11. ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
    12. if (ret)
    13. return ERR_PTR(ret);
    14. plane_state = plane->funcs->atomic_duplicate_state(plane);
    15. if (!plane_state)
    16. return ERR_PTR(-ENOMEM);
    17. state->planes[index].state = plane_state;
    18. state->planes[index].ptr = plane;
    19. state->planes[index].old_state = plane->state;
    20. state->planes[index].new_state = plane_state;
    21. plane_state->state = state;
    22. DRM_DEBUG_ATOMIC("Added [PLANE:%d:%s] %p state to %p\n",
    23. plane->base.id, plane->name, plane_state, state);
    24. if (plane_state->crtc) {
    25. struct drm_crtc_state *crtc_state;
    26. crtc_state = drm_atomic_get_crtc_state(state,
    27. plane_state->crtc);
    28. if (IS_ERR(crtc_state))
    29. return ERR_CAST(crtc_state);
    30. }
    31. return plane_state;
    32. }

          drm_atomic_get_plane_state--> plane_state = plane->funcs->atomic_duplicate_state(plane);

    2.3 drm_atomic_get_connector_state

    1. struct drm_connector_state *
    2. drm_atomic_get_connector_state(struct drm_atomic_state *state,
    3. struct drm_connector *connector)
    4. {
    5. int ret, index;
    6. struct drm_mode_config *config = &connector->dev->mode_config;
    7. struct drm_connector_state *connector_state;
    8. WARN_ON(!state->acquire_ctx);
    9. ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
    10. if (ret)
    11. return ERR_PTR(ret);
    12. index = drm_connector_index(connector);
    13. if (index >= state->num_connector) {
    14. struct __drm_connnectors_state *c;
    15. int alloc = max(index + 1, config->num_connector);
    16. c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL);
    17. if (!c)
    18. return ERR_PTR(-ENOMEM);
    19. state->connectors = c;
    20. memset(&state->connectors[state->num_connector], 0,
    21. sizeof(*state->connectors) * (alloc - state->num_connector));
    22. state->num_connector = alloc;
    23. }
    24. if (state->connectors[index].state)
    25. return state->connectors[index].state;
    26. connector_state = connector->funcs->atomic_duplicate_state(connector);
    27. if (!connector_state)
    28. return ERR_PTR(-ENOMEM);
    29. drm_connector_get(connector);
    30. state->connectors[index].state = connector_state;
    31. state->connectors[index].old_state = connector->state;
    32. state->connectors[index].new_state = connector_state;
    33. state->connectors[index].ptr = connector;
    34. connector_state->state = state;
    35. DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d:%s] %p state to %p\n",
    36. connector->base.id, connector->name,
    37. connector_state, state);
    38. if (connector_state->crtc) {
    39. struct drm_crtc_state *crtc_state;
    40. crtc_state = drm_atomic_get_crtc_state(state,
    41. connector_state->crtc);
    42. if (IS_ERR(crtc_state))
    43. return ERR_CAST(crtc_state);
    44. }
    45. return connector_state;
    46. }

          drm_atomic_get_connector_state--> connector_state = connector->funcs->atomic_duplicate_state(connector);

    2.4 struct __drm_{object}_state

            该函数触发复制state操作后,还会将复制后的state及原本的state填入drm_atomic_state中对应的__drm_{object}_state中。

    1. struct __drm_{object}_state {
    2. struct drm_{object} *ptr;
    3. struct drm_{object}_state *state, *old_state, *new_state;
    4. /* extra fields may exist */
    5. };
    1. state->connectors[index].state = connector_state;
    2. state->connectors[index].old_state = connector->state;
    3. state->connectors[index].new_state = connector_state;
    4. state->connectors[index].ptr = connector;
    5. connector_state->state = state;

            这里的old_state保存drm_{object}现有的state,而statenew_state就保存我们复制后的state。

  • 相关阅读:
    gcc 9版本 使用std::thread时候 的链接错误 undefined reference to `pthread_create‘
    粒子群算法(PSO)优化最小二乘支持向量机回归预测,PSO-LSSVM回归预测,多输入单输出模型。
    MPI之通信模式(标准,缓存,同步,就绪)
    pytorch的searchsorted解释
    Vivado使用入门之四:时序约束操作大全
    Flink(Pometheus监控)
    Shell:判断当前用户
    优秀工具|使用Reqable替换处理过的动态混淆js
    【HR】胜任力相关资料--20230915
    【算法题】反转链表(头插法、C++实现、力扣第206题、剑指offer第24题)
  • 原文地址:https://blog.csdn.net/yangguoyu8023/article/details/129261013