DRM(Direct Rendering Manager) 是 Linux 内核中的一个子系统,主要用于管理和控制现代显卡的图形显示功能。它为用户空间的图形应用程序提供直接访问图形硬件的接口,从而实现高效的 2D 和 3D 渲染以及视频输出。DRM 负责处理 GPU 和显示输出设备的管理,并与内核的其他子系统(如 KMS 和 GEM)配合工作,以实现更高效的图形处理。
DRM 的核心组成部分:
-
KMS(Kernel Mode Setting):
- KMS 是 DRM 的一部分,负责设置显示设备的分辨率、刷新率、色深等。
- KMS 控制显示设备的资源管理,比如帧缓冲(Framebuffer)的分配和切换。
-
GEM(Graphics Execution Manager):
- GEM 是用于管理 GPU 内存的 DRM 子系统,负责缓冲区分配、映射和 GPU 任务调度。
-
Buffer Management:
- DRM 框架中使用缓冲区(Buffer)来存储图形数据,如帧缓冲区,用于向显示设备提供图像。
-
DRM Driver:
- 每个支持 DRM 的显卡厂商都会提供相应的 DRM 驱动,来对接用户空间和内核空间的图形操作。例如,Intel、AMD、NVIDIA 提供了各自的 DRM 驱动程序。
DRM 操作流程:
- 初始化显卡资源和缓冲区。
- 设置显示模式(分辨率、刷新率等)。
- 渲染图像并将其传输到缓冲区。
- 将缓冲区内容传递到显示设备进行显示。
========================================
9月27更新
看了一下,tinydrm直接也有st7735的驱动。好,这次一并拿下。
DRM的示例程序:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <sys/mman.h>
#include <string.h>
int main() {
int drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
if (drm_fd < 0) {
perror("Cannot open /dev/dri/card0");
exit(1);
}
// 获取资源
drmModeRes *resources = drmModeGetResources(drm_fd);
if (!resources) {
perror("drmModeGetResources failed");
close(drm_fd);
exit(1);
}
// 查找连接器
drmModeConnector *connector = NULL;
for (int i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(drm_fd, resources->connectors[i]);
if (connector->connection == DRM_MODE_CONNECTED) {
break;
}
drmModeFreeConnector(connector);
connector = NULL;
}
if (!connector) {
perror("No connected connector found");
drmModeFreeResources(resources);
close(drm_fd);
exit(1);
}
// 查找第一个支持的模式
drmModeModeInfo mode = connector->modes[0];
// 获取显示控制器 (CRTC)
drmModeCrtc *crtc = drmModeGetCrtc(drm_fd, resources->crtcs[0]);
// 创建帧缓冲
uint32_t fb;
int width = mode.hdisplay;
int height = mode.vdisplay;
int stride = width * 4; // 4 bytes per pixel (32-bit color)
int size = stride * height;
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
handles[0] = 0;
pitches[0] = stride;
offsets[0] = 0;
// 使用 Dumb Buffer 创建 Framebuffer
struct drm_mode_create_dumb create_dumb = {};
create_dumb.width = width;
create_dumb.height = height;
create_dumb.bpp = 32;
if (ioctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) < 0) {
perror("DRM_IOCTL_MODE_CREATE_DUMB failed");
drmModeFreeResources(resources);
close(drm_fd);
exit(1);
}
handles[0] = create_dumb.handle;
pitches[0] = create_dumb.pitch;
// 分配 framebuffer
if (drmModeAddFB(drm_fd, width, height, 24, 32, pitches[0], handles[0], &fb) < 0) {
perror("drmModeAddFB failed");
drmModeFreeResources(resources);
close(drm_fd);
exit(1);
}
// 映射 framebuffer 到内存
struct drm_mode_map_dumb map_dumb = {};
map_dumb.handle = create_dumb.handle;
if (ioctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb) < 0) {
perror("DRM_IOCTL_MODE_MAP_DUMB failed");
drmModeFreeResources(resources);
close(drm_fd);
exit(1);
}
void *fb_ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, map_dumb.offset);
if (fb_ptr == MAP_FAILED) {
perror("mmap failed");
drmModeFreeResources(resources);
close(drm_fd);
exit(1);
}
// 将 framebuffer 清空(全黑)
memset(fb_ptr, 0, size);
// 设置 CRTC 并显示 framebuffer
if (drmModeSetCrtc(drm_fd, crtc->crtc_id, fb, 0, 0, &connector->connector_id, 1, &mode) < 0) {
perror("drmModeSetCrtc failed");
munmap(fb_ptr, size);
drmModeFreeResources(resources);
close(drm_fd);
exit(1);
}
printf("Framebuffer set to %dx%d\n", width, height);
// 等待5秒后退出
sleep(5);
// 清理
munmap(fb_ptr, size);
drmModeRmFB(drm_fd, fb);
drmModeFreeCrtc(crtc);
drmModeFreeConnector(connector);
drmModeFreeResources(resources);
close(drm_fd);
return 0;
}
学习 DRM (Direct Rendering Manager) 是理解 Linux 系统中的显示管理和 GPU 驱动开发的关键部分。以下是在树莓派系统上学习 DRM 的步骤和建议:
### 1. **准备开发环境**
- 使用最新的树莓派 OS,确保你有一个 Raspberry Pi 4 或者更高版本(如 Raspberry Pi 5),它们的 GPU 支持更好。
- 安装开发工具:
```bash
sudo apt update
sudo apt install build-essential git libdrm-dev linux-headers-$(uname -r)
```
- 获取 Linux 内核源码:
```bash
git clone https://github.com/raspberrypi/linux.git
cd linux
```### 2. **阅读 DRM 源码**
- 在 Linux 内核的 `drivers/gpu/drm/` 目录下有 DRM 驱动的核心代码,建议从 `drm_drv.c`, `drm_fb_helper.c`, 和 `drm_mode_config.c` 开始阅读,理解 DRM 驱动框架的基本工作方式。### 3. **从简单的 DRM 示例程序开始**
- 先从编写简单的用户空间应用程序开始,使用 `libdrm` 与 DRM 内核接口进行交互。可以参考 `libdrm` 的文档以及一些简单的 DRM 例子程序,如:
- [DRM Simple Test](https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset.c)
- 使用 `kmscube` 工具来展示 DRM 驱动的基本功能。
```bash
sudo apt install kmscube
kmscube
```### 4. **理解 Framebuffer 和 KMS**
- 树莓派系统在使用 DRM 时往往会涉及到 KMS (Kernel Mode Setting),它管理模式设置(如分辨率、刷新率等)和图形输出。可以通过 `/dev/dri/card0` 设备文件进行访问。
- 学习如何使用 Framebuffer (`/dev/fb0`) 与 DRM 进行结合操作。### 5. **修改或编写 DRM 驱动**
- 如果希望深入学习,可以尝试修改树莓派的 DRM 驱动或编写自定义驱动程序。树莓派的 DRM 驱动位于 `drivers/gpu/drm/vc4/`(对于 VideoCore GPU)。
- 阅读 [树莓派 DRM 驱动开发文档](https://www.raspberrypi.org/documentation/computers/linux_kernel.html) 或相关的驱动开发指南。### 6. **调试和日志输出**
- DRM 提供了丰富的调试支持,使用 `dmesg` 命令查看内核日志,可以找到 DRM 相关的输出。你可以在模块加载时启用更详细的日志:
```bash
sudo modprobe drm debug=0x1ff
dmesg | grep drm
```### 7. **学习资源**
- Linux DRM 文档:`Documentation/gpu/drm-kms.rst`(内核源码中)。
- [DRM kernel documentation](https://drm.pages.freedesktop.org/doc/): Freedesktop 的 DRM 官方文档。
- [DRM and KMS Overview](https://www.collabora.com/news-and-blog/blog/2021/10/14/drm-kms-introduction-part-1/):Collabora 的 DRM/KMS 概述。通过从用户空间程序入手,逐步深入到内核驱动层面,是学习 DRM 在树莓派上的一个有效途径。
待补充