Skip to content

Instantly share code, notes, and snippets.

@bombless
Created February 15, 2026 13:15
Show Gist options
  • Select an option

  • Save bombless/cd9a0ad3fac149f65e18ed9e9bbf01d2 to your computer and use it in GitHub Desktop.

Select an option

Save bombless/cd9a0ad3fac149f65e18ed9e9bbf01d2 to your computer and use it in GitHub Desktop.
// 文件名: drm_demo.c
// 编译: gcc drm_demo.c -o drm_demo -ldrm -lxf86drm
// 运行: 需要在纯控制台(tty)下,并以root权限执行 (sudo ./drm_demo)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#define WIDTH 640
#define HEIGHT 480
int main() {
int drm_fd;
drmModeRes *res;
drmModeConnector *conn = NULL;
drmModeEncoder *enc = NULL;
uint32_t crtc_id;
uint32_t connector_id;
drmModeModeInfo mode;
struct drm_mode_create_dumb creq;
struct drm_mode_map_dumb mreq;
uint32_t fb_id, handle;
uint32_t *map;
int ret;
// 1. 打开DRM设备
drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
if (drm_fd < 0) {
perror("无法打开 /dev/dri/card0");
return -1;
}
printf("成功打开DRM设备\n");
// 2. 获取Master权限 (需要root)
ret = drmSetMaster(drm_fd);
if (ret) {
perror("无法成为DRM Master,请确保以root运行且在纯控制台");
close(drm_fd);
return -1;
}
// 3. 获取资源并找到第一个可用的连接器和CRTC
res = drmModeGetResources(drm_fd);
if (!res) {
perror("无法获取DRM资源");
close(drm_fd);
return -1;
}
// 找到第一个状态为"已连接"的连接器
for (int i = 0; i < res->count_connectors; i++) {
conn = drmModeGetConnector(drm_fd, res->connectors[i]);
if (conn->connection == DRM_MODE_CONNECTED) {
printf("找到已连接的连接器 ID: %d\n", conn->connector_id);
break;
}
drmModeFreeConnector(conn);
conn = NULL;
}
if (!conn) {
fprintf(stderr, "未找到已连接的连接器\n");
goto out_free_res;
}
// 使用连接器的第一个显示模式
mode = conn->modes[0];
printf("选定显示模式: %s (%dx%d)\n", mode.name, mode.hdisplay, mode.vdisplay);
// 找到可用的编码器和CRTC
for (int i = 0; i < res->count_encoders; i++) {
enc = drmModeGetEncoder(drm_fd, res->encoders[i]);
for (int j = 0; j < res->count_crtcs; j++) {
// 检查编码器是否可能连接到这个CRTC
if (enc->possible_crtcs & (1 << j)) {
crtc_id = res->crtcs[j];
printf("选定CRTC ID: %d\n", crtc_id);
break;
}
}
if (crtc_id) break; // 找到了就跳出外层循环
drmModeFreeEncoder(enc);
enc = NULL;
}
if (!crtc_id) {
fprintf(stderr, "未找到可用的CRTC\n");
goto out_free_conn;
}
connector_id = conn->connector_id;
// 4. 创建 dumb buffer
memset(&creq, 0, sizeof(creq));
creq.width = WIDTH;
creq.height = HEIGHT;
creq.bpp = 32; // 32位色,每像素4字节
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
if (ret) {
perror("无法创建 dumb buffer");
goto out_free_enc;
}
handle = creq.handle;
printf("创建 dumb buffer, handle: %d, size: %ld, pitch: %d\n", handle, creq.size, creq.pitch);
// 5. 添加帧缓冲 (framebuffer),关联这个 buffer
ret = drmModeAddFB(drm_fd, WIDTH, HEIGHT, 24, creq.bpp,
creq.pitch, handle, &fb_id);
if (ret) {
perror("无法添加帧缓冲 (drmModeAddFB)");
goto out_destroy_dumb;
}
printf("创建帧缓冲, fb_id: %d\n", fb_id);
// 6. 准备内存映射
memset(&mreq, 0, sizeof(mreq));
mreq.handle = handle;
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (ret) {
perror("无法获取 map offset");
goto out_rm_fb;
}
// 7. 将 buffer 映射到用户空间
map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED,
drm_fd, mreq.offset);
if (map == MAP_FAILED) {
perror("mmap 失败");
goto out_rm_fb;
}
// 8. 绘制:将整个屏幕填充为红色 (ARGB格式,A为0)
// 注意:以 uint32_t 指针操作,循环赋值
for (int j = 0; j < (creq.size / 4); j++) {
map[j] = 0x00FF0000; // 在ARGB中,这是红色 (A=0, R=255, G=0, B=0)
}
printf("已绘制红色到缓冲区\n");
// 9. 关键一步:使用 drmModeSetCrtc 激活显示
ret = drmModeSetCrtc(drm_fd, crtc_id, fb_id,
0, 0, &connector_id, 1, &mode);
if (ret) {
perror("drmModeSetCrtc 失败,无法开启显示");
goto out_munmap;
}
printf("CRTC设置成功,画面应该已经显示。程序将暂停10秒...\n");
// 保持画面10秒,以便观察
sleep(10);
// 10. 清理工作
out_munmap:
munmap(map, creq.size);
out_rm_fb:
drmModeRmFB(drm_fd, fb_id);
out_destroy_dumb:
// 销毁 dumb buffer
struct drm_mode_destroy_dumb dreq = {.handle = handle};
drmIoctl(drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
out_free_enc:
if (enc) drmModeFreeEncoder(enc);
out_free_conn:
drmModeFreeConnector(conn);
out_free_res:
drmModeFreeResources(res);
close(drm_fd);
printf("程序退出。\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment