当前位置: 首页 > article >正文

DRM系列六:Drm之KMS

KMS(Kernel Mode Setting)是负责显示输出的核心组件,它处理与plane、crtc、encoder和connector相关的各项任务。简单来说,KMS就是结构体drm_mode_config、drm_mode_object和组件(object)的结合。

KMS=drm_mode_config + drm_mode_object + 组件(object)

一、drm_mode_config、drm_mode_object和组件(object)的关系

object是由drm_mode_object描述,通过type来确定对象类型,由 dev->mode_config.object_idr 申请过来的 idr来获取object的id。

struct drm_mode_object {
    uint32_t id;  // 由 dev->mode_config.object_idr 申请过来的 idr, 本质是查找object的索引
    uint32_t type;  // obj 类型, 不同的 type 表示不同的对象.
    struct drm_object_properties *properties; // 最多支持 24 个 properties
    struct kref refcount;
    void (*free_cb)(struct kref *kref);  // 释放回调接口
};

drm_mode_config、drm_mode_object以及object的关系如下图所示:
在这里插入图片描述

二、代码中组件间的联系

2内核驱动中的初始化

/* 初始化 DRM 设备*/
drm_mode_config_init(dev);

/* 注册 CRTC*/
dev->mode_config.funcs = &my_crtc_funcs;
drm_crtc_init(dev, &my_crtc, &my_crtc_helper_funcs);

/* 注册 Encoder*/
drm_encoder_init(dev, &my_encoder, &my_encoder_funcs, DRM_MODE_ENCODER_TMDS);

/* 注册 Connector*/
drm_connector_init(dev, &my_connector, &my_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);

/* 注册 Plane*/
drm_plane_init(dev, &my_plane, DRM_PLANE_TYPE_PRIMARY);

2.1drm_mode_config_init

作用主要是初始化 drm_device->mode_config 结构体和设置资源管理机制,确保资源能够自动释放。

static inline int drm_mode_config_init(struct drm_device *dev)
{
	return drmm_mode_config_init(dev);
}

int drmm_mode_config_init(struct drm_device *dev)
{
	mutex_init(&dev->mode_config.mutex);
	drm_modeset_lock_init(&dev->mode_config.connection_mutex);
	mutex_init(&dev->mode_config.idr_mutex);
	mutex_init(&dev->mode_config.fb_lock);
	mutex_init(&dev->mode_config.blob_lock);
	INIT_LIST_HEAD(&dev->mode_config.fb_list);
	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
	INIT_LIST_HEAD(&dev->mode_config.connector_list);
	INIT_LIST_HEAD(&dev->mode_config.encoder_list);
	INIT_LIST_HEAD(&dev->mode_config.property_list);
	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
	INIT_LIST_HEAD(&dev->mode_config.plane_list);
	INIT_LIST_HEAD(&dev->mode_config.privobj_list);
	idr_init(&dev->mode_config.object_idr);
	idr_init(&dev->mode_config.tile_idr);
	ida_init(&dev->mode_config.connector_ida);
	spin_lock_init(&dev->mode_config.connector_list_lock);

	init_llist_head(&dev->mode_config.connector_free_list);
	INIT_WORK(&dev->mode_config.connector_free_work, drm_connector_free_work_fn);

	drm_mode_create_standard_properties(dev);

	/* Just to be sure */
	dev->mode_config.num_fb = 0;
	dev->mode_config.num_connector = 0;
	dev->mode_config.num_crtc = 0;
	dev->mode_config.num_encoder = 0;
	dev->mode_config.num_total_plane = 0;

	if (IS_ENABLED(CONFIG_LOCKDEP)) {
		struct drm_modeset_acquire_ctx modeset_ctx;
		struct ww_acquire_ctx resv_ctx;
		struct dma_resv resv;
		int ret;

		dma_resv_init(&resv);

		drm_modeset_acquire_init(&modeset_ctx, 0);
		ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
				       &modeset_ctx);
		if (ret == -EDEADLK)
			ret = drm_modeset_backoff(&modeset_ctx);

		ww_acquire_init(&resv_ctx, &reservation_ww_class);
		ret = dma_resv_lock(&resv, &resv_ctx);
		if (ret == -EDEADLK)
			dma_resv_lock_slow(&resv, &resv_ctx);

		dma_resv_unlock(&resv);
		ww_acquire_fini(&resv_ctx);

		drm_modeset_drop_locks(&modeset_ctx);
		drm_modeset_acquire_fini(&modeset_ctx);
		dma_resv_fini(&resv);
	}

	return drmm_add_action_or_reset(dev, drm_mode_config_init_release,
					NULL);
}
2.1.1drm_mode_create_standard_properties

作用是提供一组通用的属性接口,方便用户空间程序和内核驱动之间的交互,属性通常有blob、range、enum、object等,例如属性enum的“SRC_W”,“SRC_H”等。

static int drm_mode_create_standard_properties(struct drm_device *dev)
{
	struct drm_property *prop;
	int ret;

	ret = drm_connector_create_standard_properties(dev);
	if (ret)
		return ret;

	prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
					"type", drm_plane_type_enum_list,
					ARRAY_SIZE(drm_plane_type_enum_list));
	if (!prop)
		return -ENOMEM;
	dev->mode_config.plane_type_property = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"SRC_X", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_src_x = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"SRC_Y", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_src_y = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"SRC_W", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_src_w = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"SRC_H", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_src_h = prop;
	...
	}

2.2组件之间的关联

组件之间的关联通过以下方式建立

CRTC 和 Encoder:

drm_mode_connector_attach_encoder(&my_connector, &my_encoder);
drm_encoder_helper_add(&my_encoder, &my_encoder_helper_funcs);

Encoder 和 Connector:

drm_connector_attach_encoder(&my_connector, &my_encoder);

Plane 和 CRTC:

drm_plane_helper_add(&my_plane, &my_plane_helper_funcs);

2.3用户空间配置 KMS 组件

用户空间程序(如 Wayland 或 Xorg)通过 DRM API 配置 KMS 组件。例如:

使用 drmModeSetCrtc 设置 CRTC 的显示模式。

使用 drmModeSetPlane 配置 Plane 的显示内容。

使用 drmModeConnectorSetProperty 设置 Connector 的属性(如分辨率、刷新率)。

2.4 KMS 的数据流

KMS 的数据流如下:

a.用户空间渲染:

用户空间程序将渲染好的图像放入 Framebuffer。

b.配置显示模式:

用户空间程序通过 DRM API 配置 CRTC、Encoder 和 Connector 的显示模式。

c.提交 Framebuffer:

用户空间程序将 Framebuffer 的内容提交给 Plane。

d.显示图像:

CRTC 从 Plane 中读取 Framebuffer 的内容,生成显示时序信号。

Encoder 将信号转换为物理接口支持的格式。

Connector 将信号发送到显示器。

一个简单的KMS配置实例

/* 获取 Connector*/
drmModeConnector *connector = drmModeGetConnector(fd, connector_id);

/* 获取 Encoder*/
drmModeEncoder *encoder = drmModeGetEncoder(fd, connector->encoder_id);

/* 获取 CRTC*/
drmModeCrtc *crtc = drmModeGetCrtc(fd, encoder->crtc_id);

/* 设置显示模式*/
drmModeSetCrtc(fd, crtc->crtc_id, fb_id, 0, 0, &connector->connector_id, 1, &connector->modes[0]);

/* 提交 Framebuffer*/
drmModeSetPlane(fd, plane_id, crtc->crtc_id, fb_id, 0, 0, 0, width, height, 0, 0, width << 16, height << 16);

http://www.kler.cn/a/528933.html

相关文章:

  • Java线程认识和Object的一些方法ObjectMonitor
  • jvm - GC篇
  • 《苍穹外卖》项目学习记录-Day10订单状态定时处理
  • Flutter_学习记录_Tab的简单Demo~真的很简单
  • C#面试常考随笔7:什么是匿名⽅法?还有Lambda表达式?
  • 需求分析应该从哪些方面来着手做?
  • 线程的状态转换和调度
  • 深入理解Spring框架:从基础到实践
  • python学opencv|读取图像(五十三)原理探索:使用cv.matchTemplate()函数实现最佳图像匹配
  • 996引擎 -地图-添加安全区
  • 群速度与相速度辨析
  • NIST的 临床质量指标的简介
  • arkui-x 页面封装为自定义组件,巧用controller
  • Spring的AOP思想中事物管理注意点
  • 基础数据类型之整形
  • (leetcode 213 打家劫舍ii)
  • Games104——游戏引擎Gameplay玩法系统:基础AI
  • 从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(动态菜单组件实现)
  • Dijkstra算法解析
  • 读书笔记-《Redis设计与实现》(一)数据结构与对象(下)
  • 课题介绍:水下惯性/地形组合导航精度提升的理论与方法研究
  • oracle: 多表查询之联合查询[交集intersect, 并集union,差集minus]
  • 环形缓冲区原理与C语言实现ringbuffer
  • 计算满足特定条件的素数在全体素数中的密度极限值,并将该极限值乘以10^7后向下取整的解题思路
  • Python3 【装饰器】项目实战:5个新颖的学习案例
  • 说说Redis的内存淘汰策略?