DRM学习笔记

官方文档:https://www.kernel.org/doc/html/latest/gpu/drm-internals.html

本文参考的源码版本:

  1. Linux kernel: v6.10-12030-g66ebbdfdeb09
  2. libdrm: commit b0815faa

关于 Linux 下的 Graphics 架构,以及 DRM 在其中扮演什么样的角色,可以参考下面的文章:

  1. Graphics Stack总结(一)Linux Graphics Stack简介
  2. Linux DRM(五) -- Libdrm 库

关于 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 函数中找到。

<未完待续>

posted @   青石小白  阅读(104)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示