DRM全解析 —— CREATE_DUMB(3)

news2025/1/15 13:07:07

接前一篇文章:DRM全解析 —— CREATE_DUMB(2)

本文参考以下博文:

DRM驱动(三)之CREATE_DUMB

特此致谢!

上一回讲解了drm_mode_create_dumb函数的前半部分,本回讲解余下的部分。

为了便于理解,再次贴出drm_mode_create_dumb函数代码,在drivers/gpu/drm/drm_dumb_buffers.c中,如下:

/**
 * DOC: overview
 *
 * The KMS API doesn't standardize backing storage object creation and leaves it
 * to driver-specific ioctls. Furthermore actually creating a buffer object even
 * for GEM-based drivers is done through a driver-specific ioctl - GEM only has
 * a common userspace interface for sharing and destroying objects. While not an
 * issue for full-fledged graphics stacks that include device-specific userspace
 * components (in libdrm for instance), this limit makes DRM-based early boot
 * graphics unnecessarily complex.
 *
 * Dumb objects partly alleviate the problem by providing a standard API to
 * create dumb buffers suitable for scanout, which can then be used to create
 * KMS frame buffers.
 *
 * To support dumb objects drivers must implement the &drm_driver.dumb_create
 * and &drm_driver.dumb_map_offset operations (the latter defaults to
 * drm_gem_dumb_map_offset() if not set). Drivers that don't use GEM handles
 * additionally need to implement the &drm_driver.dumb_destroy operation. See
 * the callbacks for further details.
 *
 * Note that dumb objects may not be used for gpu acceleration, as has been
 * attempted on some ARM embedded platforms. Such drivers really must have
 * a hardware-specific ioctl to allocate suitable buffer objects.
 */
 
int drm_mode_create_dumb(struct drm_device *dev,
			 struct drm_mode_create_dumb *args,
			 struct drm_file *file_priv)
{
	u32 cpp, stride, size;
 
	if (!dev->driver->dumb_create)
		return -ENOSYS;
	if (!args->width || !args->height || !args->bpp)
		return -EINVAL;
 
	/* overflow checks for 32bit size calculations */
	if (args->bpp > U32_MAX - 8)
		return -EINVAL;
	cpp = DIV_ROUND_UP(args->bpp, 8);
	if (cpp > U32_MAX / args->width)
		return -EINVAL;
	stride = cpp * args->width;
	if (args->height > U32_MAX / stride)
		return -EINVAL;
 
	/* test for wrap-around */
	size = args->height * stride;
	if (PAGE_ALIGN(size) == 0)
		return -EINVAL;
 
	/*
	 * handle, pitch and size are output parameters. Zero them out to
	 * prevent drivers from accidentally using uninitialized data. Since
	 * not all existing userspace is clearing these fields properly we
	 * cannot reject IOCTL with garbage in them.
	 */
	args->handle = 0;
	args->pitch = 0;
	args->size = 0;
 
	return dev->driver->dumb_create(file_priv, dev, args);
}

在做了参数检查后,先将参数args中的handle、pitch、size清零,确保健壮性,因为用户空间可能对这几个值并没有做清零操作就传了下来。之后调用dev->drivrer->dumb_create函数(实际上是dumb_create函数指针所指向的函数),并返回它的返回值。

在分析最后这个函数之前,先来看一下围绕DRM_IOCTL_MODE_CREATE_DUMB宏的用户态和内核态上下调用流程,如下图所示:

接下来对于dev->driver->dumb_create()进行解析。前文已提到,dev->driver->dumb_create的意思就是调用DRM设备的驱动中的dumb_create这一函数指针所指向的函数。那么它到底指向了哪个函数呢?

实际上具体所指向的函数是视dev->driver不同而不同的,对于不同的显卡驱动,dumb_create指向不同的函数。这里以笔者实际接触过的两款显卡Intel和AMD为例进行说明。

  • Intel i915

Intel i915显卡驱动对应的struct drm_driver初始化代码在drivers/gpu/drm/i915/i915_driver.c中,如下:

static const struct drm_driver i915_drm_driver = {
	/* Don't use MTRRs here; the Xserver or userspace app should
	 * deal with them for Intel hardware.
	 */
	.driver_features =
	    DRIVER_GEM |
	    DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ |
	    DRIVER_SYNCOBJ_TIMELINE,
	.release = i915_driver_release,
	.open = i915_driver_open,
	.lastclose = i915_driver_lastclose,
	.postclose = i915_driver_postclose,

	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
	.gem_prime_import = i915_gem_prime_import,

	.dumb_create = i915_gem_dumb_create,
	.dumb_map_offset = i915_gem_dumb_mmap_offset,

	.ioctls = i915_ioctls,
	.num_ioctls = ARRAY_SIZE(i915_ioctls),
	.fops = &i915_driver_fops,
	.name = DRIVER_NAME,
	.desc = DRIVER_DESC,
	.date = DRIVER_DATE,
	.major = DRIVER_MAJOR,
	.minor = DRIVER_MINOR,
	.patchlevel = DRIVER_PATCHLEVEL,
};

由代码可见,dumb_create函数指针指向了i915_gem_dumb_create函数。该函数在drivers/gpu/drm/i915/gem/i915_gem_create.c中,代码如下:

int
i915_gem_dumb_create(struct drm_file *file,
		     struct drm_device *dev,
		     struct drm_mode_create_dumb *args)
{
	struct drm_i915_gem_object *obj;
	struct intel_memory_region *mr;
	enum intel_memory_type mem_type;
	int cpp = DIV_ROUND_UP(args->bpp, 8);
	u32 format;

	switch (cpp) {
	case 1:
		format = DRM_FORMAT_C8;
		break;
	case 2:
		format = DRM_FORMAT_RGB565;
		break;
	case 4:
		format = DRM_FORMAT_XRGB8888;
		break;
	default:
		return -EINVAL;
	}

	/* have to work out size/pitch and return them */
	args->pitch = ALIGN(args->width * cpp, 64);

	/* align stride to page size so that we can remap */
	if (args->pitch > intel_plane_fb_max_stride(to_i915(dev), format,
						    DRM_FORMAT_MOD_LINEAR))
		args->pitch = ALIGN(args->pitch, 4096);

	if (args->pitch < args->width)
		return -EINVAL;

	args->size = mul_u32_u32(args->pitch, args->height);

	mem_type = INTEL_MEMORY_SYSTEM;
	if (HAS_LMEM(to_i915(dev)))
		mem_type = INTEL_MEMORY_LOCAL;

	mr = intel_memory_region_by_type(to_i915(dev), mem_type);

	obj = __i915_gem_object_create_user(to_i915(dev), args->size, &mr, 1);
	if (IS_ERR(obj))
		return PTR_ERR(obj);

	return i915_gem_publish(obj, file, &args->size, &args->handle);
}

暂时不深入分析该函数的细节,只关注最后调用的i915_gem_publish函数。i915_gem_publish函数在同文件(drivers/gpu/drm/i915/gem/i915_gem_create.c)中,代码如下:

static int i915_gem_publish(struct drm_i915_gem_object *obj,
			    struct drm_file *file,
			    u64 *size_p,
			    u32 *handle_p)
{
	u64 size = obj->base.size;
	int ret;

	ret = drm_gem_handle_create(file, &obj->base, handle_p);
	/* drop reference from allocate - handle holds it now */
	i915_gem_object_put(obj);
	if (ret)
		return ret;

	*size_p = size;
	return 0;
}

其中的核心函数为drm_gem_handle_create。

  • AMD Raedon

AMD显卡有两款驱动:Raedon和AMDGPU。

先说Raedon驱动。Raedon显卡驱动对应的struct drm_driver初始化代码在drivers/gpu/drm/radeon/radeon_drv.c中,如下:

static const struct drm_driver kms_driver = {
	.driver_features =
	    DRIVER_GEM | DRIVER_RENDER | DRIVER_MODESET,
	.load = radeon_driver_load_kms,
	.open = radeon_driver_open_kms,
	.postclose = radeon_driver_postclose_kms,
	.lastclose = radeon_driver_lastclose_kms,
	.unload = radeon_driver_unload_kms,
	.ioctls = radeon_ioctls_kms,
	.num_ioctls = ARRAY_SIZE(radeon_ioctls_kms),
	.dumb_create = radeon_mode_dumb_create,
	.dumb_map_offset = radeon_mode_dumb_mmap,
	.fops = &radeon_driver_kms_fops,

	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
	.gem_prime_import_sg_table = radeon_gem_prime_import_sg_table,
	.gem_prime_mmap = drm_gem_prime_mmap,

	.name = DRIVER_NAME,
	.desc = DRIVER_DESC,
	.date = DRIVER_DATE,
	.major = KMS_DRIVER_MAJOR,
	.minor = KMS_DRIVER_MINOR,
	.patchlevel = KMS_DRIVER_PATCHLEVEL,
};

由代码可见,dumb_create函数指针指向了radeon_mode_dumb_create函数。该函数在drivers/gpu/drm/radeon/radeon_gem.c中,代码如下:

int radeon_mode_dumb_create(struct drm_file *file_priv,
			    struct drm_device *dev,
			    struct drm_mode_create_dumb *args)
{
	struct radeon_device *rdev = dev->dev_private;
	struct drm_gem_object *gobj;
	uint32_t handle;
	int r;

	args->pitch = radeon_align_pitch(rdev, args->width,
					 DIV_ROUND_UP(args->bpp, 8), 0);
	args->size = (u64)args->pitch * args->height;
	args->size = ALIGN(args->size, PAGE_SIZE);

	r = radeon_gem_object_create(rdev, args->size, 0,
				     RADEON_GEM_DOMAIN_VRAM, 0,
				     false, &gobj);
	if (r)
		return -ENOMEM;

	r = drm_gem_handle_create(file_priv, gobj, &handle);
	/* drop reference from allocate - handle holds it now */
	drm_gem_object_put(gobj);
	if (r) {
		return r;
	}
	args->handle = handle;
	return 0;
}

其中的核心函数也是drm_gem_handle_create。

  • AMD AMDGPU

再来看AMDGPU驱动。AMDGPU显卡驱动对应的struct drm_driver初始化代码在drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c中,如下:

static const struct drm_driver amdgpu_kms_driver = {
	.driver_features =
	    DRIVER_ATOMIC |
	    DRIVER_GEM |
	    DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ |
	    DRIVER_SYNCOBJ_TIMELINE,
	.open = amdgpu_driver_open_kms,
	.postclose = amdgpu_driver_postclose_kms,
	.lastclose = amdgpu_driver_lastclose_kms,
	.ioctls = amdgpu_ioctls_kms,
	.num_ioctls = ARRAY_SIZE(amdgpu_ioctls_kms),
	.dumb_create = amdgpu_mode_dumb_create,
	.dumb_map_offset = amdgpu_mode_dumb_mmap,
	.fops = &amdgpu_driver_kms_fops,
	.release = &amdgpu_driver_release_kms,

	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
	.gem_prime_import = amdgpu_gem_prime_import,
	.gem_prime_mmap = drm_gem_prime_mmap,

	.name = DRIVER_NAME,
	.desc = DRIVER_DESC,
	.date = DRIVER_DATE,
	.major = KMS_DRIVER_MAJOR,
	.minor = KMS_DRIVER_MINOR,
	.patchlevel = KMS_DRIVER_PATCHLEVEL,
};

由代码可见,dumb_create函数指针指向了amdgpu_mode_dumb_create函数。该函数在drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c中,代码如下:

int amdgpu_mode_dumb_create(struct drm_file *file_priv,
			    struct drm_device *dev,
			    struct drm_mode_create_dumb *args)
{
	struct amdgpu_device *adev = drm_to_adev(dev);
	struct drm_gem_object *gobj;
	uint32_t handle;
	u64 flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
		    AMDGPU_GEM_CREATE_CPU_GTT_USWC |
		    AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
	u32 domain;
	int r;

	/*
	 * The buffer returned from this function should be cleared, but
	 * it can only be done if the ring is enabled or we'll fail to
	 * create the buffer.
	 */
	if (adev->mman.buffer_funcs_enabled)
		flags |= AMDGPU_GEM_CREATE_VRAM_CLEARED;

	args->pitch = amdgpu_gem_align_pitch(adev, args->width,
					     DIV_ROUND_UP(args->bpp, 8), 0);
	args->size = (u64)args->pitch * args->height;
	args->size = ALIGN(args->size, PAGE_SIZE);
	domain = amdgpu_bo_get_preferred_domain(adev,
				amdgpu_display_supported_domains(adev, flags));
	r = amdgpu_gem_object_create(adev, args->size, 0, domain, flags,
				     ttm_bo_type_device, NULL, &gobj);
	if (r)
		return -ENOMEM;

	r = drm_gem_handle_create(file_priv, gobj, &handle);
	/* drop reference from allocate - handle holds it now */
	drm_gem_object_put(gobj);
	if (r) {
		return r;
	}
	args->handle = handle;
	return 0;
}

其中的核心函数也是drm_gem_handle_create。

可见,不论是哪种显卡驱动,最终都调用了drm_gem_handle_create函数。对于这个函数的解析,请看下回。

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

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

相关文章

函数的递归调用

1、什么是函数的递归调用&#xff1f; 其实说白了就是在函数的内部再调用函数自己本身 function fun(){fun() } 2、用递归解决问题的条件 &#xff08;1&#xff09;一个问题是可以分解成子问题&#xff0c;子问题的解决办法与最原始的问题解决方法相同 &#xff08;2&…

【V4L2】V4L2框架简述

系列文章目录 【V4L2】V4L2框架简述 【V4L2】V4L2框架之驱动结构体 【V4L2】V4L2子设备 文章目录 系列文章目录V4L2框架简介V4L2框架蓝图蓝图解构层级解构 导读&#xff1a;V4L2 是专门为 linux 设备设计的一套视频框架&#xff0c;其主体框架在 linux 内核&#xff0c;可以理…

Nacos 开源版的使用测评

文章目录 一、Nacos的使用二、Nacos和Eureka在性能、功能、控制台体验、上下游生态和社区体验的对比&#xff1a;三、记使使用Nacos中容易犯的错误四、对Nacos开源提出的一些需求 一、Nacos的使用 这里配置mysql的连接方式&#xff0c;spring.datasource.platformmysql是老版本…

Python与STM32串口通讯

最近&#xff0c;苦于STM32与上位机Python的串口通讯&#xff0c;实在完成不了通讯&#xff0c;不知道到底是什么原因&#xff0c;STM32与上位机的串口调试软件是可以成功完成数据传输的&#xff0c;但用Python就不知道为啥不能完成通信&#xff0c;网上关于这方面的东西也不能…

Python Opencv实践 - 霍夫圆检测(Hough Circles)

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/steelpipes.jpg") print(img.shape) plt.imshow(img[:,:,::-1])#转为二值图 gray cv.cvtColor(img, cv.COLOR_BGR2GRAY) plt.imshow(gray, cmap plt.cm.gray…

iPhone 15预售:获取关键信息

既然苹果公司将于9月12日正式举办iPhone 15发布会,我们了解所有新机型只是时间问题。如果你是苹果的狂热粉丝,或者只是一个早期用户,那么活动结束后,你会想把所有的注意力都集中在iPhone 15的预购上——这样你就可以保证自己在发布日会有一款机型。 有很多理由对今年的iPh…

myspl使用指南

mysql数据库 使用命令行工具连接数据库 mysql -h -u 用户名 -p -u表示后面是用户名-p表示后面是密码-h表示后面是主机名&#xff0c;登录当前设备可省略。 如我们要登录本机用户名为root&#xff0c;密码为123456的账户&#xff1a; mysql -u root -p按回车&#xff0c;然后…

时序预测 | MATLAB实现TCN-BiGRU时间卷积双向门控循环单元时间序列预测

时序预测 | MATLAB实现TCN-BiGRU时间卷积双向门控循环单元时间序列预测 目录 时序预测 | MATLAB实现TCN-BiGRU时间卷积双向门控循环单元时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现TCN-BiGRU时间卷积双向门控循环单元时间序列预测&a…

“MyBatis中的关联关系配置与多表查询“

目录 引言一、一对多关系配置二、一对一关系配置三、多对多关系配置总结 引言 在数据库应用开发中&#xff0c;经常会遇到需要查询多个表之间的关联关系的情况。MyBatis是一个流行的Java持久层框架&#xff0c;它提供了灵活的配置方式来处理多表查询中的一对多、一对一和多对多…

浅谈视频汇聚平台EasyCVR中AI中台的应用功能

AI中台是将人工智能技术如深度学习、计算机视觉、知识图谱、自然语言理解等模块化&#xff0c;集约硬件的计算能力、算法的训练能力、模型的部署能力、基础业务的展现能力等人工智能能力&#xff0c;结合中台的数据资源&#xff0c;封装成整体中台系统。 在EasyCVR视频共享融合…

windows的redis配置sentinel

1、先安装好redis主从&#xff0c;参考我的文章&#xff0c;链接如下 redis主从&#xff08;windows版本&#xff09;_rediswindows版本_veminhe的博客-CSDN博客 2、然后配置sentinel 参考在windows上搭建redis集群&#xff08;Redis-Sentinel&#xff09; 配置时&#xf…

520页(17万字)集团大数据平台整体解决方案word

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除&#xff0c;更多浏览公众号&#xff1a;智慧方案文库 1.1.1 系统总体逻辑结构 4-14系统总体逻辑结构图 参见上图&#xff0c;基于Hadoop构建的企业级数据仓库&#xff0c;包含…

文心一言全面开放,可能笑傲“AIGC”江湖?

8月31日凌晨&#xff0c;百度率先向全社会全面开放“文心一言”体验&#xff0c;所有用户可在AppStore或各大安卓应用市场下载“文心一言App或登录文心一言官网”体验。 这对早早关注人工智能领域的科技咖来说&#xff0c;是个好消息。 那么&#xff0c;AIGC、大模型、文心一…

uniapp 微信小程序添加隐私保护指引

隐私弹窗&#xff1a; <uni-popup ref"popup"><view class"popupWrap"><view class"popupTxt">在你使用【最美万年历】之前&#xff0c;请仔细阅读<text class"blueColor" click"handleOpenPrivacyContract…

港联证券|杭州亚运会概念崛起 杭州园林、杭州解百等涨停

杭州亚运会概念1日盘中大幅拉升&#xff0c;截至发稿&#xff0c;杭州园林、杭州解百、中装建造等涨停&#xff0c;万事利、曼卡龙涨超8%&#xff0c;三江购物、汉嘉设计、浙江建造等涨超6%&#xff0c;君亭酒店、电魂网络涨逾5%。 音讯面上&#xff0c;杭州亚运会将于2023年9…

MyBatis-Plus快速实现增删改[MyBatis-Plus系列]

师傅&#xff1a;徒儿&#xff0c;看你最近情绪波动很大呀&#xff0c;这是怎么了&#xff1f; ​ 悟纤&#xff1a;还不是感情的事情来着。 师傅&#xff1a;怎么说来着&#xff1f; 悟纤&#xff1a;感情中间产生了太多的误会了&#xff0c;乱的很&#xff0c;老天爷给设置…

3.(Python数模)整数规划问题

Python解决整数规划问题 在实际生活中&#xff0c;线性规划中的变量不可能都是连续的值&#xff0c;比如不可能计算出0.5个人&#xff0c;0.5只牛羊&#xff0c;往往需要根据题目需要或者实际问题来调整决策变量的变量类型 Continuous’ 表示连续变量&#xff08;默认值&…

使用axi_quad_spi操作spi_flash

文章目录 基本测试情况IP支持的命令 基本测试情况 有spi_flash需要访问&#xff0c;为简单计&#xff0c;选择使用axi_quad_spi进行操作。开始时&#xff0c;将IP配置成如下参数&#xff0c; 这样配置&#xff0c;是想着能够适应各家的FLASH&#xff08;实际使用的则是micron…

业务安全情报第二十一期 | 打击代抢票“黄牛”

目录 疯狂的演出票 博物馆门票也疯狂 “黄牛”们的代抢票是什么&#xff1f; 代抢“黄牛”的牟利方式 “黄牛”代抢票的危害 技术上防范“黄牛”的代抢 抢票&#xff0c;成为关键词2023年暑假。博物馆的门票需要抢&#xff0c;各个演唱会的门票也需要抢&#xff0c;甚至高…

2023年03月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;拼点游戏 C和S两位同学一起玩拼点游戏。有一堆白色卡牌和一堆蓝色卡牌&#xff0c;每张卡牌上写了一个整数点数。C随机抽取n张白色卡牌&#xff0c;S随机抽取n张蓝色卡牌&#xff0c;他们进行n回合拼点&#xff0c;每次两人各出一张卡牌&#xff0c;点数大者获…