DRM学习笔记
官方文档:https://www.kernel.org/doc/html/latest/gpu/drm-internals.html
本文参考的源码版本:
- Linux kernel: v6.10-12030-g66ebbdfdeb09
- libdrm: commit b0815faa
关于 Linux 下的 Graphics 架构,以及 DRM 在其中扮演什么样的角色,可以参考下面的文章:
关于 libdrm
The DRM layer provides several services to graphics drivers, many of them driven by the application interfaces it provides through libdrm, the library that wraps most of the DRM ioctls. These include vblank event handling, memory management, output management, framebuffer management, command submission & fencing, suspend/resume support, and DMA services.
按照以上说法,libdrm 只是一个运行在 user mode 的 DRM 包装层,通过 ioctrl 来进入 kernel mode 执行 DRM 模块的各种功能。
直接看一看源码就明白了:https://gitlab.freedesktop.org/mesa/drm
以 amdgpu-symbols.txt
文件中的函数 amdgpu_bo_alloc
为例,它会调到下面的函数:
/**
* Send a device-specific read-write command.
*
* \param fd file descriptor.
* \param drmCommandIndex command index
* \param data source pointer of the data to be read and written.
* \param size size of the data to be read and written.
*
* \return zero on success, or a negative value on failure.
*
* \internal
* It issues a read-write ioctl given by
* \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
*/
drm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
void *data, unsigned long size)
{
unsigned long request;
request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
DRM_COMMAND_BASE + drmCommandIndex, size);
if (drmIoctl(fd, request, data))
return -errno;
return 0;
}
DRM 基本概念
DRM driver 初始化
The struct drm_driver structure contains static information that describes the driver and features it supports, and pointers to methods that the DRM core will call to implement the DRM API.
struct drm_driver
定义在 include\drm\drm_drv.h
文件中:
/**
* struct drm_driver - DRM driver structure
*
* This structure represent the common code for a family of cards. There will be
* one &struct drm_device for each card present in this family. It contains lots
* of vfunc entries, and a pile of those probably should be moved to more
* appropriate places like &drm_mode_config_funcs or into a new operations
* structure for GEM drivers.
*/
struct drm_driver {
...
如何创建一个这样数据结构的对象呢?以AMD的GPU为例,在文件 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,
.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,
.gem_prime_import_sg_table = radeon_gem_prime_import_sg_table,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = KMS_DRIVER_MAJOR,
.minor = KMS_DRIVER_MINOR,
.patchlevel = KMS_DRIVER_PATCHLEVEL,
};
那么它的用法呢?主要用于 drm_dev_alloc
来创建 DRM device:
/**
* drm_dev_alloc - Allocate new DRM device
* @driver: DRM driver to allocate device for
* @parent: Parent device object
*
* This is the deprecated version of devm_drm_dev_alloc(), which does not support
* subclassing through embedding the struct &drm_device in a driver private
* structure, and which does not support automatic cleanup through devres.
*
* RETURNS:
* Pointer to new DRM device, or ERR_PTR on failure.
*/
struct drm_device *drm_dev_alloc(const struct drm_driver *driver,
struct device *parent)
{
...
注意:上面函数注释中提到,这个函数已经被新的函数 devm_drm_dev_alloc
所取代。
创建 device 对象并充分初始化后,我们需要注册这个 device 对象,使得用户空间也可以访问它:
/**
* drm_dev_register - Register DRM device
* @dev: Device to register
* @flags: Flags passed to the driver's .load() function
*
* Register the DRM device @dev with the system, advertise device to user-space
* and start normal device operation. @dev must be initialized via drm_dev_init()
* previously.
*
* Never call this twice on any device!
*
* NOTE: To ensure backward compatibility with existing drivers method this
* function calls the &drm_driver.load method after registering the device
* nodes, creating race conditions. Usage of the &drm_driver.load methods is
* therefore deprecated, drivers must perform all initialization before calling
* drm_dev_register().
*
* RETURNS:
* 0 on success, negative error code on failure.
*/
int drm_dev_register(struct drm_device *dev, unsigned long flags)
{
...
上面的完整逻辑对应的代码可以在文件 drivers\gpu\drm\radeon\radeon_drv.c
中的 radeon_pci_probe
函数中找到。
<未完待续>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通