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

目录

[1. drm_atomic_state_alloc创建drm_atomic_state](#1. drm_atomic_state_alloc创建drm_atomic_state)

[1.1 drm_atomic_state_init](#1.1 drm_atomic_state_init)

[2. 各个drm object对应的state](#2. 各个drm object对应的state)

[2.1 drm_atomic_get_crtc_state](#2.1 drm_atomic_get_crtc_state)

[2.2 drm_atomic_get_plane_state](#2.2 drm_atomic_get_plane_state)

[2.3 drm_atomic_get_connector_state](#2.3 drm_atomic_get_connector_state)

[2.4 struct _drm{object}_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接口。

用户态相关接口:

cpp 复制代码
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表示。

cpp 复制代码
​
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的继承关系如下图:

1. drm_atomic_state_alloc创建drm_atomic_state

cpp 复制代码
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进行初始化。

1.1 drm_atomic_state_init

cpp 复制代码
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中几个指针指向的内存区域。

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

cpp 复制代码
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);

2.2 drm_atomic_get_plane_state

cpp 复制代码
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);

2.3 drm_atomic_get_connector_state

cpp 复制代码
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);

2.4 struct _drm{object}_state

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

cpp 复制代码
struct __drm_{object}_state {
        struct drm_{object} *ptr;
        struct drm_{object}_state *state, *old_state, *new_state;
    
        /* extra fields may exist */
};
cpp 复制代码
	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,而statenew_state就保存我们复制后的state。

相关推荐
芒果黑3 个月前
Qt WebEngine播放DRM音视频
drm·qt webengine
炭烤毛蛋10 个月前
modetest
drm·framebuffer
wenshizhang1 年前
AMD显卡休眠唤醒流程分析
linux·内核·drm·amdgpu
Android系统攻城狮1 年前
Android12之DRM架构(一)
drm
蓝天居士1 年前
DRM全解析 —— connector详解(1)
drm
蓝天居士1 年前
DRM全解析 —— encoder详解(3)
drm
蓝天居士1 年前
DRM全解析 —— encoder详解(1)
drm
山东布谷科技官方1 年前
直播系统源码平台内容安全与版权维护技术:DRM
网络安全·drm·直播系统源码·数字版权管理·版权
蓝天居士1 年前
DRM全解析 —— CREATE_DUMB(4)
linux内核·libdrm·drm