目录
1. drm_atomic_state_alloc创建drm_atomic_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接口。
用户态相关接口:
- typedef struct _drmModeAtomicReq drmModeAtomicReq, *drmModeAtomicReqPtr;
-
- extern drmModeAtomicReqPtr drmModeAtomicAlloc(void);
- extern drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr req);
- extern int drmModeAtomicMerge(drmModeAtomicReqPtr base,
- drmModeAtomicReqPtr augment);
- extern void drmModeAtomicFree(drmModeAtomicReqPtr req);
- extern int drmModeAtomicGetCursor(drmModeAtomicReqPtr req);
- extern void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor);
- extern int drmModeAtomicAddProperty(drmModeAtomicReqPtr req,
- uint32_t object_id,
- uint32_t property_id,
- uint64_t value);
- extern int drmModeAtomicCommit(int fd,
- drmModeAtomicReqPtr req,
- uint32_t flags,
- 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表示。
-
- struct drm_atomic_state {
- struct kref ref;
-
- struct drm_device *dev;
- bool allow_modeset : 1;
- bool legacy_cursor_update : 1;
- bool async_update : 1;
- struct __drm_planes_state *planes;
- struct __drm_crtcs_state *crtcs;
- int num_connector;
- struct __drm_connnectors_state *connectors;
- int num_private_objs;
- struct __drm_private_objs_state *private_objs;
-
- struct drm_modeset_acquire_ctx *acquire_ctx;
-
- struct work_struct commit_work;
- };
drm_atomic_state和其他组件state的继承关系如下图:

- struct drm_atomic_state *
- drm_atomic_state_alloc(struct drm_device *dev)
- {
- struct drm_mode_config *config = &dev->mode_config;
-
- if (!config->funcs->atomic_state_alloc) {
- struct drm_atomic_state *state;
-
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
- return NULL;
- if (drm_atomic_state_init(dev, state) < 0) {
- kfree(state);
- return NULL;
- }
- return state;
- }
-
- return config->funcs->atomic_state_alloc(dev);
- }
函数中可以看到,drm_mode_config_funcs中提供了名为atomic_state_alloc的hook,允许我们自己实现state对象的创建。在默认情况下,函数会调用简单分配内存,然后使用drm_atomic_state_init进行初始化。
- int
- drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
- {
- kref_init(&state->ref);
-
- /* TODO legacy paths should maybe do a better job about
- * setting this appropriately?
- */
- state->allow_modeset = true;
-
- state->crtcs = kcalloc(dev->mode_config.num_crtc,
- sizeof(*state->crtcs), GFP_KERNEL);
- if (!state->crtcs)
- goto fail;
- state->planes = kcalloc(dev->mode_config.num_total_plane,
- sizeof(*state->planes), GFP_KERNEL);
- if (!state->planes)
- goto fail;
-
- state->dev = dev;
-
- DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state);
-
- return 0;
- fail:
- drm_atomic_state_default_release(state);
- return -ENOMEM;
- }
初始化函数仅仅是简单分配分配drm_atomic_state中几个指针指向的内存区域。
对于各个drm object对应的state,其创建操作由其对应的drm_{object}_funcs->atomic_duplicate_state实现,在驱动程序没有扩展drm_atomic_state的情况下,这个回调函数一般填写为drm_atomic_helper_{object}_duplicate_state。
- struct drm_crtc_state *
- drm_atomic_get_crtc_state(struct drm_atomic_state *state,
- struct drm_crtc *crtc)
- {
- int ret, index = drm_crtc_index(crtc);
- struct drm_crtc_state *crtc_state;
-
- WARN_ON(!state->acquire_ctx);
-
- crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
- if (crtc_state)
- return crtc_state;
-
- ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
- if (ret)
- return ERR_PTR(ret);
-
- crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
- if (!crtc_state)
- return ERR_PTR(-ENOMEM);
-
- state->crtcs[index].state = crtc_state;
- state->crtcs[index].old_state = crtc->state;
- state->crtcs[index].new_state = crtc_state;
- state->crtcs[index].ptr = crtc;
- crtc_state->state = state;
-
- DRM_DEBUG_ATOMIC("Added [CRTC:%d:%s] %p state to %p\n",
- crtc->base.id, crtc->name, crtc_state, state);
-
- return crtc_state;
- }
drm_atomic_get_crtc_state--> crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
- struct drm_plane_state *
- drm_atomic_get_plane_state(struct drm_atomic_state *state,
- struct drm_plane *plane)
- {
- int ret, index = drm_plane_index(plane);
- struct drm_plane_state *plane_state;
-
- WARN_ON(!state->acquire_ctx);
-
- plane_state = drm_atomic_get_existing_plane_state(state, plane);
- if (plane_state)
- return plane_state;
-
- ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
- if (ret)
- return ERR_PTR(ret);
-
- plane_state = plane->funcs->atomic_duplicate_state(plane);
- if (!plane_state)
- return ERR_PTR(-ENOMEM);
-
- state->planes[index].state = plane_state;
- state->planes[index].ptr = plane;
- state->planes[index].old_state = plane->state;
- state->planes[index].new_state = plane_state;
- plane_state->state = state;
-
- DRM_DEBUG_ATOMIC("Added [PLANE:%d:%s] %p state to %p\n",
- plane->base.id, plane->name, plane_state, state);
-
- if (plane_state->crtc) {
- struct drm_crtc_state *crtc_state;
-
- crtc_state = drm_atomic_get_crtc_state(state,
- plane_state->crtc);
- if (IS_ERR(crtc_state))
- return ERR_CAST(crtc_state);
- }
-
- return plane_state;
- }
drm_atomic_get_plane_state--> plane_state = plane->funcs->atomic_duplicate_state(plane);
- struct drm_connector_state *
- drm_atomic_get_connector_state(struct drm_atomic_state *state,
- struct drm_connector *connector)
- {
- int ret, index;
- struct drm_mode_config *config = &connector->dev->mode_config;
- struct drm_connector_state *connector_state;
-
- WARN_ON(!state->acquire_ctx);
-
- ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
- if (ret)
- return ERR_PTR(ret);
-
- index = drm_connector_index(connector);
-
- if (index >= state->num_connector) {
- struct __drm_connnectors_state *c;
- int alloc = max(index + 1, config->num_connector);
-
- c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL);
- if (!c)
- return ERR_PTR(-ENOMEM);
-
- state->connectors = c;
- memset(&state->connectors[state->num_connector], 0,
- sizeof(*state->connectors) * (alloc - state->num_connector));
-
- state->num_connector = alloc;
- }
-
- if (state->connectors[index].state)
- return state->connectors[index].state;
-
- connector_state = connector->funcs->atomic_duplicate_state(connector);
- if (!connector_state)
- return ERR_PTR(-ENOMEM);
-
- drm_connector_get(connector);
- state->connectors[index].state = connector_state;
- state->connectors[index].old_state = connector->state;
- state->connectors[index].new_state = connector_state;
- state->connectors[index].ptr = connector;
- connector_state->state = state;
-
- DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d:%s] %p state to %p\n",
- connector->base.id, connector->name,
- connector_state, state);
-
- if (connector_state->crtc) {
- struct drm_crtc_state *crtc_state;
-
- crtc_state = drm_atomic_get_crtc_state(state,
- connector_state->crtc);
- if (IS_ERR(crtc_state))
- return ERR_CAST(crtc_state);
- }
-
- return connector_state;
- }
drm_atomic_get_connector_state--> connector_state = connector->funcs->atomic_duplicate_state(connector);
该函数触发复制state操作后,还会将复制后的state及原本的state填入drm_atomic_state中对应的__drm_{object}_state中。
- struct __drm_{object}_state {
- struct drm_{object} *ptr;
- struct drm_{object}_state *state, *old_state, *new_state;
-
- /* extra fields may exist */
- };
- state->connectors[index].state = connector_state;
- state->connectors[index].old_state = connector->state;
- state->connectors[index].new_state = connector_state;
- state->connectors[index].ptr = connector;
- connector_state->state = state;
这里的old_state保存drm_{object}现有的state,而state及new_state就保存我们复制后的state。