DRM驱动(七)之atomic_commit

2023-11-14

上节已经把应用的参数check了一遍,这次就可以把对应的参数配置到硬件里进行刷图操作了

int drm_atomic_commit(struct drm_atomic_state *state)
{
	struct drm_mode_config *config = &state->dev->mode_config;
	int ret;

	ret = drm_atomic_check_only(state);
	if (ret)
		return ret;

	DRM_DEBUG_ATOMIC("committing %p\n", state);

	return config->funcs->atomic_commit(state->dev, state, false);
}

config->funcs->atomic_commit是drm驱动初始化时创建的,可以由soc厂商实现也可以使用drm框架中的drm_atomic_helper_commit,如rockchip的驱动

static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
	.fb_create = rockchip_user_fb_create,
	.output_poll_changed = rockchip_drm_output_poll_changed,
	.atomic_check = drm_atomic_helper_check,
	.atomic_commit = drm_atomic_helper_commit,
};

drm_atomic_helper_commit

我们重点分析下drm_atomic_helper_commit的主要内容

  1. 初始化一个工作队列,应用如果使用noblock的方式刷图,就使用此工作队列,这样驱动可以直接返回给应用,让应用做其他事情
  2. 交换state,将要刷新的state赋给各组件的state,将上次刷新的state保存到state结构体中
  3. 根据是否采用noblock方式刷图来决定如何调用commit_tail
int drm_atomic_helper_commit(struct drm_device *dev,
     struct drm_atomic_state *state,
     bool nonblock)
{
... ...
    INIT_WORK(&state->commit_work, commit_work);
... ...
	ret = drm_atomic_helper_swap_state(state, true);
	if (ret)
		goto err;
... ...
	if (nonblock)
		queue_work(system_unbound_wq, &state->commit_work);
	else
		commit_tail(state);

	return 0;
}
int drm_atomic_helper_swap_state(struct drm_atomic_state *state,
  bool stall)
{
	for_each_oldnew_connector_in_state(state, connector, old_conn_state, new_conn_state, i) {
		WARN_ON(connector->state != old_conn_state);

		old_conn_state->state = state;
		new_conn_state->state = NULL;

		state->connectors[i].state = old_conn_state;
		connector->state = new_conn_state;
	}

	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
		WARN_ON(crtc->state != old_crtc_state);

		old_crtc_state->state = state;
		new_crtc_state->state = NULL;

		state->crtcs[i].state = old_crtc_state;
		crtc->state = new_crtc_state;
	}

	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
		WARN_ON(plane->state != old_plane_state);

		old_plane_state->state = state;
		new_plane_state->state = NULL;

		state->planes[i].state = old_plane_state;
		plane->state = new_plane_state;
	}

	for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) {
		WARN_ON(obj->state != old_obj_state);

		old_obj_state->state = state;
		new_obj_state->state = NULL;

		state->private_objs[i].state = old_obj_state;
		obj->state = new_obj_state;
	}

	return 0;
}

从代码可以看到如果noblock被置位,将启动commit_work,否则调用commit_tail

static void commit_work(struct work_struct *work)
{
	struct drm_atomic_state *state = container_of(work,
		  struct drm_atomic_state,
		  commit_work);
	commit_tail(state);
}

commit_work中调用的也是commit_tail.

commit_tail中主要进行一些fence等事件的判断,和drm_atomic_helper_commit_tail

fence的内容我们现在不作为重点,我们主要看刷图相关内容,刷图主要在drm_atomic_helper_commit_tail里面,如果soc厂商有实现atomic_commit_tail,将调用soc实现的接口

static void commit_tail(struct drm_atomic_state *old_state)
{
	struct drm_device *dev = old_state->dev;
	const struct drm_mode_config_helper_funcs *funcs;

	funcs = dev->mode_config.helper_private;

	drm_atomic_helper_wait_for_fences(dev, old_state, false);

	drm_atomic_helper_wait_for_dependencies(old_state);

	if (funcs && funcs->atomic_commit_tail)
		funcs->atomic_commit_tail(old_state);
	else
		drm_atomic_helper_commit_tail(old_state);

	drm_atomic_helper_commit_cleanup_done(old_state);

	drm_atomic_state_put(old_state);
}

drm_atomic_helper_commit_tail

drm_atomic_helper_commit_tail调用的几个函数比较复杂,决定用几个思维导图介绍下。

drm_atomic_helper_commit_modeset_disables

  1. 如果mode发生改变其实就是state->mode_changed state->active_changed state->connectors_changed,状态被置位(上节atomic_check中有聊到在哪里置位的)就会关掉crtc,和encoder;图中带颜色的均是soc厂商需要根据硬件行为实现的接口,比如关掉显示和tcon等等
  2. crtc_set_mode中,如果active被置位,并且上面mode_changed等状态被置位则调用crtc->helper_private->mode_set_nofb和encoder的modeset函数,来将对应mode设置到配置到硬件,同样这些回调需要soc厂商来实现。

总结一句话:如果只是mode发生了变化,就先关crtc和encoder,再配置mode到crtc到encoder;如果只是状态发送变化,则只关掉crtc和encoder

drm_atomic_helper_commit_planes

此函数非常重要,因为大多数的硬件均是在这里配置的。

plane->helper_private->atomic_update(plane, old_plane_state):根据plane_state中图像大小和位置等和fb的显存地址配置layer的信息到硬件

crtc->helper_private->atomic_flush(crtc, old_crtc_state):更新除了layer的其他相关的内容,比如trigger位

这两个回调主要用到之前保存到state里的信息,后面有机会分析一下别人实现好的驱动就很好理解了。

drm_atomic_helper_commit_modeset_enables:

  1. 将之前关闭的crtc和encoder打开;配置硬件打开显示和tcon,一并打开encoder

drm_atomic_helper_commit_hw_done:上报hw_done事件,通知硬件配置已经完成。

drm_atomic_helper_wait_for_vblanks(dev, old_state):等待vblank事件,硬件更新完成之后,会等到下一个vsync中断到来后才会生效,vblank事件会在vsync中断处理函数中上报;drm中默认等待50ms,如果显示硬件出现异常超过50ms未上报vblank事件,会打印警告和堆栈

W kernel: [CRTC:35:crtc-0] vblank wait timed out
W kernel: ------------[ cut here ]------------
W kernel: WARNING: CPU: 0 PID: 24879 at gpu/drm/drm_atomic_helper.c:1240 drm_atomic_helper_wait_for_vblanks.part.7+0x2ac/0x2b8
W kernel: CPU: 0 PID: 24879 Comm: kworker/u12:5 Tainted: P        W  O L  4.14.61+ #1
W kernel: Workqueue: events_unbound commit_work
W kernel: task: ffff8000c4904880 task.stack: ffff00000d6d8000
W kernel: PC is at drm_atomic_helper_wait_for_vblanks.part.7+0x2ac/0x2b8
W kernel: LR is at drm_atomic_helper_wait_for_vblanks.part.7+0x2ac/0x2b8
W kernel: [<ffff0000086fb094>] drm_atomic_helper_wait_for_vblanks.part.7+0x2ac/0x2b8
W kernel: [<ffff0000086fb140>] drm_atomic_helper_commit_tail+0x60/0x78
W kernel: [<ffff0000086fb1e4>] commit_tail+0x8c/0x90
W kernel: [<ffff0000086fb208>] commit_work+0x20/0x30
W kernel: [<ffff0000081017e4>] process_one_work+0x1dc/0x4a8
W kernel: [<ffff000008101b00>] worker_thread+0x50/0x478
W kernel: [<ffff000008108eb8>] kthread+0x138/0x140
W kernel: [<ffff00000808518c>] ret_from_fork+0x10/0x1c

vsync中断处理函数中也会上报filpdone事件,代表新的一帧已经在硬件生效,新的一帧图像已经出现在屏幕上。

至此刷新一帧图的大致流程已分析完毕,分析过程省略了很多细节,感兴趣可以对照源码看一遍。

drm把显示的框架实现的非常完善,一些显示通用的部分有drm框架处理,差异化的内容通过回调的方式交由各个soc厂商实现,避免了重复造轮子。

后面有时间会结合一个具体的驱动分析一下drm驱动初始化的过程,包括drm的一些回调函数的功能

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DRM驱动(七)之atomic_commit 的相关文章

  • touch命令在一个目录下创建多个文件(不同名称)

    我想制作一个在 bash 中创建目录和文件结构的脚本 我尝试过这样的事情 mkdir p 1 2 touch 1 2 a b c a b c 应该是在一个命令或其他命令中创建的文件 但由于某种原因 结构是这样的 current folder
  • 将数组传递给函数名称冲突

    Specs GNU bash 版本 3 1 17 无法升级 Premise 我一直在摆弄数组 我想知道是否有任何方法可以让函数的本地变量与所述函数外部的数组同名 Example 在下面的示例中 我将尝试显示该问题 Working bin b
  • 如何成功使用RDAP协议代替whois

    我对新的 RDAP 协议有点困惑 也不知道何时进一步追求它有意义 在我看来 每个人都同意它是 whois 的继承者 但他们的数据库似乎是空的 在 ubuntu 上我尝试了 rdapper nicinfo 甚至他们的 RESTful API
  • 操作系统什么时候清除进程的内存

    进程在某些操作系统上成功或异常终止 操作系统何时决定擦除分配给该进程的内存 数据 代码等 在退出时或当它想为新进程分配内存时 这个清除内存分配过程在所有操作系统 winXP Win7 linux Mac 上都相同吗 据我了解 页表具有该进程
  • InstaPy:“错误,无法确定 64 位 Linux 的正确文件名”

    有人知道如何解决或解决这个问题吗 来自控制台的堆栈跟踪 执行后报告错误 InstaPy Version 0 6 9 Workspace in use home zanettra InstaPy Error unable to determi
  • 无法执行'x86_64-conda_cos6-linux-gnu-gcc':没有这样的文件或目录(pysam安装)

    我正在尝试安装 pysam 执行后 python path to pysam master setup py build 这个错误的产生是 unable to execute x86 64 conda cos6 linux gnu gcc
  • Linux 中热插拔设备时检测设备是否存在

    我正在运行 SPIcode http lxr free electrons com source drivers spi spi omap2 mcspi c在熊猫板上 我想知道其中的哪个功能code http lxr free electr
  • Inotify linux 监视子目录

    是否可以以这种模式监视目录 storage data usernames Download gt storage data Download 我需要监视每个用户的下载文件夹中是否进行了更改 也许我需要创建所有路径的列表 将其放入数组中 并在
  • 在 Ubuntu 16.04 上找不到 printf.c

    我最近切换到Ubuntu 16 04 我在用vscode作为 Ubuntu 上的 IDE 我配置了其他语言 但我无法做到这一点C C 我创建c cpp properties json launch json tasks json 当我开始编
  • 如何以编程方式从Linux中的进程名称获取进程ID

    在我的项目中 我们使用 ACE 自适应通信环境 中间件来编写可在 Windows 和 Linux 上运行的独立于操作系统的代码 要求是从进程名称中获取进程 ID 由于 ACE 不支持这一点 因此我们必须使用特定于平台的宏来分离 Window
  • linux x86 汇编语言 sys_read 调用的第一个参数应为 0 (stdin)

    我正在编写一个简单的汇编程序来从标准输入读取 如 scanf 这是我的代码 section bss num resb 5 section txt global start start mov eax 3 sys read mov ebx 0
  • 如何在特定 systemd 服务重新启动时触发自定义脚本运行

    我想知道如何安排自定义脚本在重新启动服务时运行 我的用例是 每当重新启动 Tomcat 服务时 我都必须运行多个命令 我想知道是否有一种方法可以编写脚本并安排它在重新启动 Tomcat 服务时运行 我已将 tomcat 脚本设置为 syst
  • 劫持系统调用

    我正在编写一个内核模块 我需要劫持 包装一些系统调用 我正在暴力破解 sys call table 地址 并使用 cr0 来禁用 启用页面保护 到目前为止一切顺利 一旦完成 我将公开整个代码 因此如果有人愿意 我可以更新这个问题 无论如何
  • arm-linux-gnueabi 编译器选项

    我在用 ARM Linux gnueabi gcc在 Linux 中为 ARM 处理器编译 C 程序 但是 我不确定它编译的默认 ARM 模式是什么 例如 对于 C 代码 test c unsigned int main return 0x
  • 在 Linux 上的 Python 中使用受密码保护的 Excel 工作表

    问题很简单 我每周都会收到一堆受密码保护的 Excel 文件 我必须解析它们并使用 Python 将某些部分写入新文件 我得到了文件的密码 当在 Windows 上完成此操作时 处理起来很简单 我只需导入 win32com 并使用 clie
  • PHP 致命错误:未找到“MongoClient”类

    我有一个使用 Apache 的网站 代码如下 当我尝试访问它时 我在 error log 中收到错误 PHP Fatal Error Class MongoClient not found 以下是可能错误的设置 但我认为没有错误 php i
  • 在 Linux 中禁用历史记录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 要在 Linux 环境中禁用历史记录 我执行了以下命令 export HISTFILESIZE 0 export HISTSIZE 0 u
  • QFileDialog::getSaveFileName 和默认的 selectedFilter

    我有 getSaveFileName 和一些过滤器 我希望当用户打开 保存 对话框时选择其中之一 Qt 文档说明如下 可以通过将 selectedFilter 设置为所需的值来选择默认过滤器 我尝试以下变体 QString selFilte
  • 在 Mac OS X 上构建 Linux 内核

    我正在做一个修改Linux内核的项目 我有一台桌面 Linux 机器 在上面构建内核没有问题 不过 我要去旅行 我想在途中工作 我只有一台 MacBook 当我尝试构建 Linux 内核时 它抱怨说elf h was not found 我
  • 强制卸载 NFS 安装目录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案

随机推荐

  • 互联网行业潜规则:宁花11k招新人,不花9k留老人

    最近一位互联网从业者发出这样的感慨 有些互联网公司 宁愿花11k招新人 也不愿意花9k留住老员工 为什么 对此 许多网友给出了答案 有的网友说 因为老员工的能量已经耗尽 再也不能为公司创造更高的价值 有的网友说 因为只要给一个老员工涨工资
  • Vmware Workstation Pro16安装

    Vmware Workstation Pro16安装 一 右击打开安装包 二 下一步 三 勾选 我接收许可协议中的条款 点击 下一步 四 修改安装路径 五 两个复选框都取消勾选 六 下一步 七 安装 八 许可证 九 完成
  • 线性表的查找算法-C语言

    文章目录 一 实验目的 二 实验内容 三 实验工具 四 实验代码 五 实验结果 六 总结与思考 一 实验目的 了解查找的基本概念 理解顺序查找 折半查找和分块查找的思想 掌握折半查找过程的判定树构造方法 实现线性表的查找算法 二 实验内容
  • mybatis中的if-else语句的使用解答

    1 mybatis中if else语句的语法 使用模板样例
  • 什么是沙箱技术?与容器有什么区别

    沙箱和容器的 隔离 机制 首先 什么是沙箱 它本身就是一种线下生活现象的虚拟化 现实世界里 小孩子们在沙地 沙滩上用木板隔离出一个方盒子 在盒子里堆砌 创造各种东西 城堡 房屋 山丘 这就是一个沙箱 它有两个根本特点 一 它有边界 通过木板
  • aix oracle 11 补丁包,oracle 11g for aix6.1安装基本步骤(含升级11.1.0.7)

    oracle 11g for aix6 1安装基本步骤 含升级11 1 0 7 1 检查物理内存 swap空间以及tmp空间 usr sbin lsattr E l sys0 a realmem 检查内存至少1G usr sbin lsps
  • anaconda创建python环境

    1 前提 系统中安装了anaconda沙箱环境 下载地址 anaconda官网 conda V 检验是否安装以及当前conda的版本 2 conda常用的命令 1 conda list 查看安装了哪些包 2 conda env list 或
  • bcd码和十进制码之间的转换

    BCD码转十进制 static u8 BCDToInt u8 value unsigned char temp 0 temp value gt gt 4 10 temp value 0x0F return temp 十进制转BCD码 sta
  • java awt linux_解决在linux下awt调用错误的问题

    在java中使用awt在服务器上处理图片的时候发现有错 第一遍执行 500 Servlet Exception java lang InternalError Can t connect to X11 window server using
  • MyBatis自动生成实体类

    MyBatis MySQL生成实体类 需要的工具jar包 mybatis generator core 1 3 2 jar mysql connector java 5 0 4 jar 第一步 编写一个MybatisGeneratorUti
  • android 之 如何让app没有图标

    我们有时候需要让我们的app没有图标 不要问我没有图标要干啥 我只是说的一个需求 单讲技术不说别的 首先我们要获得 PackageManager 的对象 PackageManager packageManager getPackageMan
  • Caffeine缓存的使用

    1 springboot集成Caffeine
  • KeePass搭建一个私人密码库

    文章作者 GoodBoyboy 文章链接 https blog goodboyboy top posts 2546190081 html 版权声明 本博客所有文章除特别声明外 均采用 CC BY NC SA 4 0 许可协议 转载请注明来自
  • 线程(进程)的同步与互斥实例

    1 有一个队列 线程1负责从网络接收分组 并将收到的分组放到队列尾 然后再次从网络中接收下一个到达的分组 并进行同样的队列操作 线程2从此队列头中取出一个分组进行处理 处理完毕后 再次从队列中取出一个分组进行处理 处理完毕后再次从队列头取出
  • [转]Python实现多功能音乐播放器

    前言 就是用Python做一个简易的音乐播放器 废话不多说 咱们直接开干 当然 今天做这个肯定不是最简单的 最简单的音乐播放器 9行代码足以 import time import pygame file r 歌曲路径 pygame mixe
  • torch.hub.load()解析,如何加载本地权重

    用yolov5训练了一个权重 项目只能部署在本地 官方文档 torch hub load repo or dir model args source github force reload False verbose True skip v
  • Python 第一阶段

    第一章 安装 1 1 开发环境 官网 https www python org稳定版 Stable Releases检验 cmd 命令 python version 1 2 开发工具 PyCharm官网 https www jetbrain
  • (Struts2学习篇) Struts2配置文件之 struts-default.xml

    对struts default xml的一些注释
  • zmq+protobuf 的坑点难点

    zmq protobuf 的坑点难点 之前项目要用到zmq protobuf的方式传递数据 软件采用前后端分离的方式开发 其中前端是异地同事用python开发的 后端是我们这边用C 开发的 1 中间有遇到问题是前后端传送zmq信息时 发现字
  • DRM驱动(七)之atomic_commit

    上节已经把应用的参数check了一遍 这次就可以把对应的参数配置到硬件里进行刷图操作了 int drm atomic commit struct drm atomic state state struct drm mode config c