Linux内核4.14版本——drm框架分析(11)——DRM_IOCTL_MODE_ADDFB2(drm_mode_addfb2)

news2025/1/18 16:51:59

目录

1. drm_mode_addfb2

2. drm_internal_framebuffer_create

3. drm_fb_cma_create->drm_gem_fb_create->drm_gem_fb_create_with_funcs

4. drm_gem_fb_alloc

 4.1 drm_helper_mode_fill_fb_struct

4.2 drm_framebuffer_init

5. 调用流程图


        书接上回,使用drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)接口创建了一块内存放在了gem cma的对象里。

        gem obj创建之后需要与一块drm_framebuffer进行绑定使用,因为最终刷图使用的是fb。使用下面接口会创建drm_framebuffer并与上节创建的gem obj进行绑定。

        目前使用较多的就是drm_mode_addfb2接口,该接口完成了下面的功能。

1. drm_mode_addfb2

int drm_mode_addfb2(struct drm_device *dev,
		    void *data, struct drm_file *file_priv)
{
	struct drm_mode_fb_cmd2 *r = data;
	struct drm_framebuffer *fb;

	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EINVAL;

	fb = drm_internal_framebuffer_create(dev, r, file_priv);
	if (IS_ERR(fb))
		return PTR_ERR(fb);

	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
	r->fb_id = fb->base.id;

	/* Transfer ownership to the filp for reaping on close */
	mutex_lock(&file_priv->fbs_lock);
	list_add(&fb->filp_head, &file_priv->fbs);
	mutex_unlock(&file_priv->fbs_lock);

	return 0;
}

       drm_mode_addfb2主要做了三件大事:

        (1)调用drm_internal_framebuffer_create创建一个drm_framebuffer。

        (2)把drm_framebuffer的struct drm_mode_object的ID返回给应用。

        (3)加到file_priv的fbs链表中。

下面我们看一下函数drm_internal_framebuffer_create。

2. drm_internal_framebuffer_create

struct drm_framebuffer *
drm_internal_framebuffer_create(struct drm_device *dev,
				const struct drm_mode_fb_cmd2 *r,
				struct drm_file *file_priv)
{
    ........

	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
	if (IS_ERR(fb)) {
		DRM_DEBUG_KMS("could not create framebuffer\n");
		return fb;
	}

	return fb;
}

        检查参数,然后调用dev->mode_config.funcs->fb_create(dev, file_priv, r),可以自己实现,也可以使用内核现成的drm_fb_cma_create。

3. drm_fb_cma_create->drm_gem_fb_create->drm_gem_fb_create_with_funcs


struct drm_framebuffer *
drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
			     const struct drm_mode_fb_cmd2 *mode_cmd,
			     const struct drm_framebuffer_funcs *funcs)
{
	const struct drm_format_info *info;
	struct drm_gem_object *objs[4];
	struct drm_framebuffer *fb;
	int ret, i;

	info = drm_get_format_info(dev, mode_cmd);
	if (!info)
		return ERR_PTR(-EINVAL);

	for (i = 0; i < info->num_planes; i++) {
		unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
		unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
		unsigned int min_size;

		objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
		if (!objs[i]) {
			DRM_DEV_ERROR(dev->dev, "Failed to lookup GEM\n");
			ret = -ENOENT;
			goto err_gem_object_put;
		}

		min_size = (height - 1) * mode_cmd->pitches[i]
			 + width * info->cpp[i]
			 + mode_cmd->offsets[i];

		if (objs[i]->size < min_size) {
			// DRM_DEV_ERROR(dev->dev, "objs %d Size(%d %d) error\n",
			// 	i, objs[i]->size, min_size);
			drm_gem_object_put_unlocked(objs[i]);
			ret = -EINVAL;
			goto err_gem_object_put;
		}
	}

	fb = drm_gem_fb_alloc(dev, mode_cmd, objs, i, funcs);
	if (IS_ERR(fb)) {
		ret = PTR_ERR(fb);
		DRM_DEV_ERROR(dev->dev, "alloc error %d\n", ret);
		goto err_gem_object_put;
	}

	return fb;

err_gem_object_put:
	for (i--; i >= 0; i--)
		drm_gem_object_put_unlocked(objs[i]);

	return ERR_PTR(ret);
}

        (1)通过应用提供的handle,使用drm_gem_object_lookup找到上次创建的gem obj。

        (2)调用drm_gem_fb_alloc,分配一个drm_framebuffer,将gem obj赋值给framebuffer中的obj。

4. drm_gem_fb_alloc

static struct drm_framebuffer *
drm_gem_fb_alloc(struct drm_device *dev,
		 const struct drm_mode_fb_cmd2 *mode_cmd,
		 struct drm_gem_object **obj, unsigned int num_planes,
		 const struct drm_framebuffer_funcs *funcs)
{
	struct drm_framebuffer *fb;
	int ret, i;

	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
	if (!fb)
		return ERR_PTR(-ENOMEM);

	drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);

	for (i = 0; i < num_planes; i++)
		fb->obj[i] = obj[i];

	ret = drm_framebuffer_init(dev, fb, funcs);
	if (ret) {
		DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n",
			      ret);
		kfree(fb);
		return ERR_PTR(ret);
	}

	return fb;
}

 4.1 drm_helper_mode_fill_fb_struct

void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
				    struct drm_framebuffer *fb,
				    const struct drm_mode_fb_cmd2 *mode_cmd)
{
	int i;

	fb->dev = dev;
	fb->format = drm_get_format_info(dev, mode_cmd);
	fb->width = mode_cmd->width;
	fb->height = mode_cmd->height;
	for (i = 0; i < 4; i++) {
		fb->pitches[i] = mode_cmd->pitches[i];
		fb->offsets[i] = mode_cmd->offsets[i];
	}
	fb->modifier = mode_cmd->modifier[0];
	fb->flags = mode_cmd->flags;
}

      将应用传入的长,宽,format,pitch,flag等填充framebuffer结构体。

4.2 drm_framebuffer_init

int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
			 const struct drm_framebuffer_funcs *funcs)
{
	int ret;

	if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
		return -EINVAL;

	INIT_LIST_HEAD(&fb->filp_head);

	fb->funcs = funcs;

	ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
				    false, drm_framebuffer_free);
	if (ret)
		goto out;

	mutex_lock(&dev->mode_config.fb_lock);
	dev->mode_config.num_fb++;
	list_add(&fb->head, &dev->mode_config.fb_list);
	mutex_unlock(&dev->mode_config.fb_lock);

	drm_mode_object_register(dev, &fb->base);
out:
	return ret;
}

        相关字段填充完成后会将fb添加进dev->mode_config.fb_list便于后面使用的时候通过id进行查找, drm的组件都是通过dev->mode_config中的链表进行管理的,只要拿到mode_config就可以拿到drm相关信息。

        至此drm_framebuffer已经创建完毕。通过r->fb_id = fb->base.id;将fb_id返回给用户。

5. 调用流程图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1007890.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot对接postgres

安装postgres 注意:下述链接方式会自动创建数据库steven_russell,若需要创建其他数据库&#xff0c;可以手动执行命令创建数据库 docker run --name postgres \ -p 5432:5432 \ -e POSTGRES_USERsteven_russell \ -e POSTGRES_PASSWORD123456 \ -itd --privilegedtrue postgre…

【卖出看涨期权策略(Short Call)】

卖出看涨期权策略&#xff08;Short Call) 卖出看涨期权策略又称为卖出无备兑看涨期权&#xff0c;如果一个投资者在不持有标的资产价格的情况下卖出看涨期权&#xff0c;那么这种策略就是卖出无备兑看涨期权策略。这个策略潜在盈利有限&#xff0c;但是亏损无限。 卖出看涨期…

基于SSM的应急资源管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Git - Git Merge VS Git Rebase

文章目录 概述Flow View小结 概述 Git merge和Git rebase是两种不同的版本控制工作流程&#xff0c;它们用于将一个分支的更改合并到另一个分支。它们有不同的工作原理和应用场景&#xff0c;下面是它们的主要区别&#xff1a; 合并的方式&#xff1a; Git Merge&#xff1a;合…

MySQL间隙锁深入分析

概念 什么是间隙锁&#xff1f; MySQL的间隙锁&#xff08;gap lock&#xff09;是一种锁定相邻数据间隔的机制。 触发时机&#xff1f; 当使用SELECT…FOR UPDATE或UPDATE语句时&#xff0c;MySQL会获取一个范围锁&#xff0c;包括指定条件内的所有数据行&#xff0c;并且还…

离散数学 学习 之 一阶逻辑基本概念 (一 )

个体词可以 理解为主语 &#xff0c; 3 不是偶数 &#xff0c;3 就是 个体常项 凡整数都能被 2 整除 &#xff0c; 整数就是 个体变项 上面的谓词是 &#xff08; 1 &#xff09; 是无理数 &#xff08; 2 &#xff09; 是有理数 &#xff08; 3 &#xff09; 与 同岁 &#xf…

四川百幕晟科技:提升店铺质量方法是什么?

抖店是抖音旗下的移动电子商务平台&#xff0c;为商家提供在线销售和促销的机会。在抖店&#xff0c;经验值是商家评价和信誉的重要指标之一。反映了平台上商户的服务质量和用户满意度。那么&#xff0c;如何查看自己在抖店手机上的体验分数呢&#xff1f; 1、如何查看抖店手机…

C# 随机数生成 Mersenne Twister 马特赛特旋转演算法 梅森旋转算法

NuGet安装MathNet.Numerics 引用: using MathNet.Numerics.Random; /// <summary>/// 包括lower&#xff0c;不包括upper/// </summary>/// <param name"lower"></param>/// <param name"upper"></param>/// <para…

老师如何私发成绩?

尊敬的各位老师&#xff0c;大家好&#xff01;你是否曾经为繁琐的成绩管理和与学生家长的沟通而感到头疼&#xff1f;是否希望有一个简单方便的工具&#xff0c;能够帮助你私发成绩、管理班级和与家长交流&#xff1f;那么&#xff0c;易查分将是你的最佳选择&#xff01;易查…

destoon根据标题删除重复数据

因为采集数据比较庞大&#xff0c;难免出现重复数据&#xff0c;所以写了一个根据标题进行删除重复数据的mysql命令&#xff0c;需要的朋友可以使用。 DELETE from destoon_article_36 where title in (SELECT * from (SELECT title FROM destoon_article_36 GROUP BY title …

想要精通算法和SQL的成长之路 - 受限条件下可到达节点的数目

想要精通算法和SQL的成长之路 - 受限条件下可到达节点的数目 前言一. 相交链表&#xff08;邻接图和DFS&#xff09; 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 相交链表&#xff08;邻接图和DFS&#xff09; 原题链接 public int reachableNodes(int n, int[][] ed…

超强干货,Pytest自动化测试框架fixture固件使用,0-1精通实战

前言 如果有以下场景&#xff1a;用例 1 需要先登录&#xff0c;用例 2 不需要登录&#xff0c;用例 3 需要先登录。很显然无法用 setup 和 teardown 来实现了 fixture 可以让我们自定义测试用例的前置条件 fixture 的优势 命名方式灵活&#xff0c;不局限于 setup 和teard…

黑马JVM总结(七)

&#xff08;1&#xff09;StringTable_编译器优化 “a”“b”对应#4&#xff1a;是去常量池中找ab的这个符号 astore 5&#xff1a;是把这个存入编号为5的局部变量 “ab”对应的指令 #4&#xff0c;跟“a”“b”对应#4下面弄是一样的 在执行s3“ab”这行个代码时&#xf…

【Python】从入门到上头—mysql数据库操作模块mysql-connector和PyMySQL应用场景 (15)

mysql-connector MySQL官方提供了mysql-connector-python驱动 安装驱动 python -m pip install mysql-connector连接数据库获取连接 import mysql.connectordb mysql.connector.connect(host"localhost", #ipuser"root", #用户名passwd"root",…

Python的命令行参数

Python的命令行参数&#xff0c;提供了很多有用的功能&#xff0c;可以方便调试和运行&#xff0c;通过man python就能查看&#xff0c;以下是一些常用参数使用实例和场景: 1. -B参数 在import时候&#xff0c;不产生pyc或者pyo文件: 比如有程序main.py如下: from Hello im…

SSM - Springboot - MyBatis-Plus 全栈体系(七)

第二章 SpringFramework 四、SpringIoC 实践和应用 3. 基于 注解 方式管理 Bean 3.4 实验四&#xff1a;Bean 属性赋值&#xff1a;基本类型属性赋值&#xff08;DI&#xff09; Value 通常用于注入外部化属性 3.4.1 声明外部配置 application.properties catalog.nameM…

UG\NX二次开发 获取装配部件的相关信息UF_ASSEM_ask_component_data

文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 简介: UG\NX二次开发 获取装配部件的相关信息UF_ASSEM_ask_component_data 包括:零件名称、引用集名称、实例名称、组件的位置、坐标系矩阵、转换矩阵。 效果: 代…

Docker基础学习

Docker 学习目标&#xff1a; 掌握Docker基础知识&#xff0c;能够理解Docker镜像与容器的概念 完成Docker安装与启动 掌握Docker镜像与容器相关命令 掌握Tomcat Nginx 等软件的常用应用的安装 掌握docker迁移与备份相关命令 能够运用Dockerfile编写创建容器的脚本 能够…

并联电容器交流耐压试验方法

对被试并联电容器两极进行充分放电。 检查电容器外观、 污秽等情况, 判断电容器是否满足试验要求状态。 用端接线将并联电容器两极短接连接湖北众拓高试工频耐压装置高压端, 外壳接地。 接线完成后经检查确认无误, 人员退出试验范围。 接入符合测试设备的工作电源&#xff0c;…

Java(二)--面向对象

十.封装 1.访问权限不用加 在c中是访问权限&#xff1a; 属性/行为&#xff1a; class Person{public:void speak(){cout<<"666";} }; 在Java中是访问权限 属性/行为&#xff1a; class Person{public void speak(){cout<<"666";} }; 2.…