libdrm 是不是通过 ioctl() 与内核 DRM/显卡通信?

Posted

技术标签:

【中文标题】libdrm 是不是通过 ioctl() 与内核 DRM/显卡通信?【英文标题】:Does libdrm talk to kernel DRM/graphics card via ioctl()?libdrm 是否通过 ioctl() 与内核 DRM/显卡通信? 【发布时间】:2020-08-26 03:14:56 【问题描述】:

这可能是一个愚蠢的问题,因为我对这个主题知之甚少......似乎用户应用程序可以直接与 GPU 对话以渲染图像,例如使用 OpenGL,通过 mesa 和 libdrm,其中libdrm 是各种 ioctl() 调用的包装器,如this graph 中所示。这是否意味着对于 3D 游戏的每个新帧,游戏应用程序都需要调用 ioctl() 一次(如果需要访问 KMS,甚至可能调用两次)?这听起来像是很多用户-内核空间障碍(考虑一个 120 fps 的游戏)。

【问题讨论】:

【参考方案1】:

libdrm 是一个用户空间包装器,用于执行对底层 KMS 驱动程序功能的细粒度访问,例如模式设置、检查所使用的平面是覆盖平面还是主平面等。对于各种 CPU/GPU/OS 组合,libdrm 实现通常不同,因为在内核中运行的硬件驱动程序倾向于支持除标准功能之外的不同功能集。使用 libdrm 的标准方法是打开 /dev/ 节点中可用的 drm 设备,并使用从 open() 返回的 fd 执行 libdrm 函数调用。

通常情况下,特定操作系统(如 X11、wayland、hardware-composer)的显示合成器软件需要控制 drm 设备,这意味着非特权应用程序无法成为 DRM 主控。如果尝试使用它们的应用程序不是 DRM 主机,则大多数 libdrm 模式设置功能都不起作用。建议的做法是使用标准图形库(如 openGL 或 VULKAN)在您的应用程序中准备和渲染帧,而不是直接使用 libdrm。

与内核 DRM 模块交互所需的 ioctl 数量很可能不是您在尝试渲染高 FPS 应用程序时将面临的最大瓶颈。在与目标系统的显示合成器合作的同时运行高 fps 应用程序的首选方法是拥有

用于渲染的双缓冲或三缓冲设置,其中要渲染的下一个缓冲区已准备好在当前帧完成渲染之前进行渲染。 尽可能利用硬件加速,例如执行缩放/调整大小/图像格式转换/色彩空间转换。 预计算和重用着色器元素 尽量重用纹理元素,而不是为每一帧渲染计算大量纹理。 尽可能使用矢量/SIMD/SSEv2、3、4/AVX/neon 指令来利用现代 CPU 管道

【讨论】:

感谢您的回答。那么最后,libdrm函数调用是使用ioctl()实现的吗?我对此感到好奇 - 用户最终需要访问内核 DRM 内部的功能,或者静态/动态加载的任何内核模块功能,而 ioctl() 在这种情况下似乎是唯一的方法,对吗?关于您的 cmets 的另一个问题,当用户有一个双缓冲区缓冲区并渲染到这些缓冲区中时,无论是 w/ 还是 w/o h/w 加速,这些渲染调用最终也需要通过 ioctl() 调用发生,对吗?跨度> 我想我的问题是——从用户空间调用内核/模块函数,或者将某些东西渲染到 RAM/VRAM 中,用户必须跨越用户/内核障碍,他只能这样做通过标准系统调用或 ioctl 调用(这是一种包罗万象的接口),没有其他方法。对吗? @QnA 没错,与内核交互以进行渲染以及在渲染帧之前使用 GPU 准备场景通过 ioctls 发生在 DRM 设备上。 DRM 子系统负责来自操作系统的 GPU 交互以及显示交互。使用 GPU/显示子系统的应用程序直接或间接使用 ioctl 与内核对话 这很有帮助,再次感谢。我知道您的回答比我最初的问题更广泛/更深入,但请多容忍我一秒钟......所以 ioctl 调用必须每帧至少(直接或间接)发生一次(并且可能更多),例如一些准备工作,然后是渲染,然后是“我完成了,去展示它”?而你所说的是,对于 120 fps 的游戏来说,每秒 120 多个 ioctl 调用与其他成本相比并没有那么昂贵,对吗? @QnA 是的,每帧必须至少发生 1 个 ioctl 调用,尤其是对于“我完成了,去显示它”。与我在答案中提到的其他领域相比,每秒 120+ ioctls 不应该是一个昂贵的命令,也不应该是应用程序的瓶颈

以上是关于libdrm 是不是通过 ioctl() 与内核 DRM/显卡通信?的主要内容,如果未能解决你的问题,请参考以下文章

ioctl 与 Linux 中的内核模块

Linux用户与内核空间交互—ioctl

Linux用户与内核空间交互—ioctl

(10)Linux 网络编程之ioctl函数

为啥 ioctl 调用没有传递给 sys_ioctl?

Linux字符设备-内核态数据与用户态数据互传