`libdrm` 是用户空间与 Linux 内核 DRM(Direct Rendering Manager)子系统之间的桥梁。它提供了一组 API,允许用户空间程序(如显示服务器、图形库)与内核 DRM 驱动进行交互,从而管理图形硬件资源(如显存、显示模式、渲染等)。
以下是 `libdrm` 和内核 DRM 驱动对接的详细说明:
## 1. **DRM 子系统概述**
DRM 是 Linux 内核中用于管理图形硬件的子系统,主要负责:
- 显存管理(如分配、释放)。
- 显示模式设置(如分辨率、刷新率)。
- 渲染和合成(如 2D/3D 加速)。
- 电源管理(如 GPU 频率调节)。
`libdrm` 是用户空间与 DRM 子系统交互的库,封装了与 DRM 驱动的通信细节。
## 2. **libdrm 和内核 DRM 驱动的对接流程**
### 2.1 **打开 DRM 设备**
用户空间程序通过 `libdrm` 打开 DRM 设备文件(如 `/dev/dri/card0`),获取文件描述符。#### 示例代码
#include <xf86drm.h>
int fd = drmOpen("card0", NULL);
if (fd < 0) {
fprintf(stderr, "Failed to open DRM device\n");
return -1;
}
- `drmOpen` 是 `libdrm` 提供的函数,用于打开 DRM 设备。
- 返回的文件描述符 `fd` 用于后续的 DRM API 调用。
### 2.2 **获取 DRM 资源**
通过 `libdrm` 获取 DRM 设备的资源信息,如 CRTC、Connector、Encoder 和 Framebuffer。#### 示例代码
#include <xf86drmMode.h>
drmModeRes *resources = drmModeGetResources(fd);
if (!resources) {
fprintf(stderr, "Failed to get DRM resources\n");
return -1;
}
// 遍历 CRTC、Connector 等资源
for (int i = 0; i < resources->count_crtcs; i++) {
printf("CRTC %d: %d\n", i, resources->crtcs[i]);
}
drmModeFreeResources(resources);
- `drmModeGetResources` 获取 DRM 设备的资源信息。
- `drmModeFreeResources` 释放资源。
### 2.3 **设置显示模式**
通过 `libdrm` 设置显示模式(如分辨率、刷新率)。#### 示例代码
drmModeConnector *connector = drmModeGetConnector(fd, connector_id);
if (!connector) {
fprintf(stderr, "Failed to get connector\n");
return -1;
}
// 选择第一个显示模式
drmModeModeInfo *mode = &connector->modes[0];
// 设置 CRTC
int ret = drmModeSetCrtc(fd, crtc_id, fb_id, 0, 0, &connector_id, 1, mode);
if (ret < 0) {
fprintf(stderr, "Failed to set CRTC\n");
return -1;
}
drmModeFreeConnector(connector);
- `drmModeGetConnector` 获取连接器(如 HDMI、DP)的信息。
- `drmModeSetCrtc` 设置 CRTC 的显示模式。
### 2.4 **分配和管理显存**
通过 `libdrm` 分配和管理显存(Framebuffer)。
#### 示例代码
#include <drm_fourcc.h>
uint32_t fb_id;
uint32_t handles[4] = {0};
uint32_t pitches[4] = {0};
uint32_t offsets[4] = {0};
// 创建 Framebuffer
int ret = drmModeAddFB2(fd, width, height, DRM_FORMAT_XRGB8888,
handles, pitches, offsets, &fb_id, 0);
if (ret < 0) {
fprintf(stderr, "Failed to create framebuffer\n");
return -1;
}
// 使用 Framebuffer
ret = drmModeSetCrtc(fd, crtc_id, fb_id, 0, 0, &connector_id, 1, mode);
if (ret < 0) {
fprintf(stderr, "Failed to set CRTC with framebuffer\n");
return -1;
}
```
- `drmModeAddFB2` 创建一个 Framebuffer。
- `drmModeSetCrtc` 将 Framebuffer 绑定到 CRTC。
### 2.5 **处理 DRM 事件**
通过 `libdrm` 处理 DRM 事件(如 VBlank、Page Flip)。#### 示例代码
drmEventContext evctx = {0};
evctx.version = DRM_EVENT_CONTEXT_VERSION;
evctx.page_flip_handler = handle_page_flip;
while (1) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
int ret = select(fd + 1, &fds, NULL, NULL, NULL);
if (ret < 0) {
fprintf(stderr, "select error\n");
break;
}
if (FD_ISSET(fd, &fds)) {
drmHandleEvent(fd, &evctx);
}
}
- `drmHandleEvent` 处理 DRM 事件。
- `handle_page_flip` 是自定义的回调函数,用于处理 Page Flip 事件。
---
## 3. **内核 DRM 驱动的实现**
内核 DRM 驱动负责与硬件交互,实现以下功能:
- **设备初始化**:在 `probe` 函数中初始化硬件。
- **资源管理**:实现显存分配、释放等功能。
- **显示模式设置**:实现 CRTC、Encoder 和 Connector 的配置。
- **事件处理**:触发 VBlank、Page Flip 等事件。
#### 示例代码(内核模块)
```c
#include <drm/drmP.h>
static struct drm_driver my_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM,
.load = my_driver_load,
.unload = my_driver_unload,
.gem_free_object = my_gem_free_object,
.ioctls = my_ioctls,
.fops = &my_fops,
};
static int __init my_driver_init(void)
{
return drm_pci_init(&my_driver, &my_pci_driver);
}
static void __exit my_driver_exit(void)
{
drm_pci_exit(&my_driver, &my_pci_driver);
}
module_init(my_driver_init);
module_exit(my_driver_exit);
```
- `my_driver_load`:初始化 DRM 设备。
- `my_gem_free_object`:释放 GEM 对象。
- `my_ioctls`:实现自定义的 IOCTL 接口。
---
## 4. **libdrm 和内核 DRM 驱动的交互**
- 主动调用,**IOCTL 接口**:
- `libdrm` 通过 `ioctl` 系统调用与内核 DRM 驱动交互。
- 内核 DRM 驱动实现了一系列 IOCTL 接口(如 `DRM_IOCTL_MODE_GETRESOURCES`、`DRM_IOCTL_MODE_SETCRTC`)。
- 主动调用 **GEM/TTM**:
- `libdrm` 使用 GEM(Graphics Execution Manager)或 TTM(Translation Table Maps)管理显存。
- 被动触发,**事件机制**:
- 内核 DRM 驱动通过事件机制(如 VBlank、Page Flip)通知用户空间。
---
## 5. **总结**
- `libdrm` 是用户空间与内核 DRM 驱动交互的库,封装了 DRM 设备的打开、资源管理、显存分配等功能。
- 内核 DRM 驱动负责与硬件交互,实现设备初始化、资源管理、显示模式设置等功能。
- 通过 `libdrm` 和内核 DRM 驱动的对接,用户空间程序可以高效地管理图形硬件资源。