DRM系列六:Drm之KMS

news/2025/2/3 13:41:30/

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 个 propertiesstruct 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.ppmy.cn/news/1568962.html

相关文章

高阶C语言|深入理解字符串函数和内存函数

文章目录 前言1.求字符串长度1.1 字符串长度函数&#xff1a;strlen模拟实现 2.长度不受限制的字符串函数2.1 字符串拷贝函数&#xff1a;strcpy模拟实现 2.2 字符串连接函数&#xff1a;strcat模拟实现 2.3 字符串比较函数&#xff1a;strcmp模拟实现 3.长度受限制的字符串函数…

【Proteus】NE555纯硬件实现LED呼吸灯效果,附源文件,效果展示

本文通过NE555定时器芯片和简单的电容充放电电路,设计了一种纯硬件实现的呼吸灯方案,并借助Proteus仿真软件验证其功能。方案无需编程,成本低且易于实现,适合电子爱好者学习PWM(脉宽调制)和定时器电路原理。 一、呼吸灯原理与NE555功能分析 1. 呼吸灯核心原理 呼吸灯的…

CMake技术细节:解决未定义,提供参数

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

浅谈知识蒸馏技术

最近爆火的DeepSeek 技术&#xff0c;将知识蒸馏技术运用推到我们面前。今天就简单介绍一下知识蒸馏技术并附上python示例代码。 知识蒸馏&#xff08;Knowledge Distillation&#xff09;是一种模型压缩技术&#xff0c;它的核心思想是将一个大型的、复杂的教师模型&#xff0…

AI编程工具使用技巧:在Visual Studio Code中高效利用阿里云通义灵码

AI编程工具使用技巧&#xff1a;在Visual Studio Code中高效利用阿里云通义灵码 前言一、通义灵码介绍1.1 通义灵码简介1.2 主要功能1.3 版本选择1.4 支持环境 二、Visual Studio Code介绍1.1 VS Code简介1.2 主要特点 三、安装VsCode3.1下载VsCode3.2.安装VsCode3.3 打开VsCod…

【自学嵌入式(8)天气时钟:天气模块开发、主函数编写】

天气时钟&#xff1a;天气模块开发、主函数编写 I2C协议和SPI协议I2C&#xff08;Inter-Integrated Circuit&#xff09;SPI&#xff08;Serial Peripheral Interface&#xff09; 天气模块心知天气预报使用HTTPClient类介绍主要功能常用函数注意事项 JSON介绍deserializeJson函…

Ubuntu全面卸载mysql

如果你已经看到whereis mysql输出了与MySQL相关的路径&#xff0c;说明MySQL仍然存在于系统中。要卸载MySQL&#xff0c;可以按照以下步骤操作&#xff0c;确保完全删除所有相关的文件和配置&#xff1a; 1. 停止MySQL服务 首先&#xff0c;停止MySQL服务&#xff1a; sudo …

架构技能(四):需求分析

需求分析&#xff0c;即分析需求&#xff0c;分析软件用户需要解决的问题。 需求分析的下一环节是软件的整体架构设计&#xff0c;需求是输入&#xff0c;架构是输出&#xff0c;需求决定了架构。 决定架构的是软件的所有需求吗&#xff1f;肯定不是&#xff0c;真正决定架构…