DRM系列六:Drm之KMS

news/2025/2/3 2:51:33 标签: java, 数据库, 开发语言, DRM, c语言

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.niftyadmin.cn/n/5840448.html

相关文章

QT知识点复习

1.qt核心机制 对象树、信号和槽、事件机制 2.对象树的作用 优化了内存回收机制。子对象实例化的时候&#xff0c;被父对象放对象树上&#xff0c;父对象释放内存&#xff0c;子对象也释放内存 3.信号和槽的作用 实现多个组件之间的通讯 4.信号和槽的几种连接方式 1.UI界面提…

第五篇:索引与查询优化

第五篇&#xff1a;索引与查询优化 目标读者&#xff1a; 本篇文章适合那些希望提高数据库性能、优化查询的学习者。无论你是开发人员、数据库管理员&#xff0c;还是数据分析师&#xff0c;掌握索引的原理和查询优化的技巧都能够显著提升数据库的响应速度&#xff0c;减少系…

【数据采集】案例01:基于Scrapy采集豆瓣电影Top250的详细数据

基于Scrapy采集豆瓣电影Top250的详细数据 Scrapy 官方文档:https://docs.scrapy.org/en/latest/豆瓣电影Top250官网:https://movie.douban.com/top250写在前面 实验目的:基于Scrapy框架采集豆瓣电影Top250的详细数据。 电脑系统:Windows 使用软件:PyCharm、Navicat Python…

GIS教程:全国数码商城系统

文章目录 注册高德地图API普通网页中测试地图加载地图添加标记地图配置点标记 Marker添加弹框创建vue项目并添加高德地图创建项目加载高德地图项目首页布局封装axios和配置代理服务器获取城市热门信息获取城市区县信息获取区县商城信息获取指定城市区县的经纬度坐标将地图缩放到…

C++ | 红黑树

前言 本篇博客讲解c中数据结构红黑树&#xff0c;看这篇博客之前请先去看&#xff1a; C | AVL树_c avl树能有重复节点吗-CSDN博客 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青…

群晖Alist套件无法挂载到群晖webdav,报错【连接被服务器拒绝】

声明&#xff1a;我不是用docker安装的 在套件中心安装矿神的Alist套件后&#xff0c;想把夸克挂载到群晖上&#xff0c;方便复制文件的&#xff0c;哪知道一直报错&#xff0c;最后发现问题出在两个地方&#xff1a; 1&#xff09;挂载的路径中&#xff0c;直接填 dav &…

蓝桥杯备考:六大排序算法

1 插入排序 算法过程 从第二个元素开始往前插入&#xff0c;比如第二个元素是7&#xff0c;我们把7存一下&#xff0c;然后和前面的元素比较&#xff0c;如果前面的元素大就把前面的元素往后移直到找到空位置插入 接下来我们把第三个元素插入到1和2的区间里面 第四个元素已经符…

【并查集】

并查集&#xff08;Disjoint Set Union&#xff0c;DSU&#xff09;是一种用于处理不相交集合的数据结构&#xff0c;主要支持两种操作&#xff1a;查找&#xff08;Find&#xff09;和合并&#xff08;Union&#xff09;。它在解决连通性问题、图论问题以及动态连通性等问题时…