Ubuntu20.04安装vGPU后分辨率锁定,如何用open调用枚举KMS模式?
Ubuntu 20.04 vGPU安装后分辨率锁定:基于DRM/KMS的解决方法
问题背景
Ubuntu 20.04安装vGPU平台后,主机分辨率被锁定,使用xrandr调整时返回错误:Failed to get size of gamma。
指导内容含义解释
通过open系统调用读取KMS文件描述符,可枚举可用的KMS模式,进而控制GPU。drmModeGetResources(drm_fd)会返回包含framebuffers、crtcs、connectors、encoders、分辨率等uint32类型项的结构体。
这段指导核心是绕过Xorg层面的工具(如xrandr),直接通过Linux内核DRM/KMS接口操作GPU——vGPU驱动可能接管了Xorg的显示控制权限,导致xrandr失效。具体拆解:
open系统调用读取KMS文件描述符:DRM设备文件位于/dev/dri/目录(如/dev/dri/card0),需用C语言open()函数打开该文件获取文件描述符(drm_fd),这是与DRM内核模块通信的入口。drmModeGetResources(drm_fd):这是DRM开发库中的C语言函数,并非终端命令或可安装包,调用它能获取GPU的所有显示资源信息,包括可用分辨率模式。
你的尝试问题分析
- 尝试1:
drmModeGetResources是DRM库函数,不是系统包,因此apt install无法找到。需安装DRM开发依赖包才能编译调用它的程序。 - 尝试2:
fbset操作的是帧缓冲设备(/dev/fb0),但vGPU环境下帧缓冲已被驱动接管,修改后无法生效。 - 尝试3:
drmModeGetResources(drm_fd)是C语言函数调用,不能直接在终端执行,必须写入C程序编译运行。
具体操作方法
步骤1:安装DRM开发依赖
先安装编译所需的基础库:
sudo apt update && sudo apt install libdrm-dev gcc
步骤2:编写DRM模式枚举程序
创建C语言文件drm_mode_list.c,内容如下:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <drm/drm.h> #include <drm/drm_mode.h> int main() { // 打开主DRM设备,多GPU环境可尝试card1 int drm_fd = open("/dev/dri/card0", O_RDWR); if (drm_fd < 0) { perror("Failed to open DRM device"); return 1; } // 获取GPU显示资源 drmModeRes *res = drmModeGetResources(drm_fd); if (!res) { perror("Failed to get DRM resources"); close(drm_fd); return 1; } printf("Available connectors:\n"); // 遍历所有显示器接口连接器 for (int i = 0; i < res->count_connectors; i++) { drmModeConnector *conn = drmModeGetConnector(drm_fd, res->connectors[i]); if (!conn) continue; printf("Connector %d: type=%d, status=%d\n", i, conn->connector_type, conn->connection); // 输出该连接器支持的所有分辨率模式 if (conn->count_modes > 0) { printf("Supported modes:\n"); for (int j = 0; j < conn->count_modes; j++) { drmModeModeInfo mode = conn->modes[j]; printf(" %dx%d@%dHz\n", mode.hdisplay, mode.vdisplay, mode.vrefresh); } } drmModeFreeConnector(conn); } drmModeFreeResources(res); close(drm_fd); return 0; }
步骤3:编译运行程序
gcc drm_mode_list.c -o drm_mode_list -ldrm sudo ./drm_mode_list
运行后会列出当前GPU支持的所有分辨率模式及对应连接器信息。
步骤4:设置目标分辨率(基于DRM接口)
如果要设置指定分辨率,可修改上述程序添加模式设置逻辑。以下是设置1920x1080@60Hz的简化示例:
- 在
drm_mode_list.c中新增设置函数:
// 新增分辨率设置函数 int set_drm_mode(int drm_fd, drmModeRes *res, drmModeConnector *conn, uint32_t crtc_id, drmModeModeInfo *mode) { drmModeEncoder *encoder = drmModeGetEncoder(drm_fd, conn->encoder_id); if (!encoder) { perror("Failed to get encoder"); return 1; } // 设置显示控制器CRTC模式 int ret = drmModeSetCrtc(drm_fd, crtc_id, 0, 0, 0, &conn->connector_id, 1, mode); if (ret < 0) { perror("Failed to set CRTC mode"); drmModeFreeEncoder(encoder); return 1; } drmModeFreeEncoder(encoder); return 0; }
- 在
main函数的连接器循环中,添加模式匹配与设置逻辑:
// 在遍历连接器的循环内,找到已连接的设备并设置目标模式 if (conn->connection == DRM_MODE_CONNECTED) { for (int j = 0; j < conn->count_modes; j++) { drmModeModeInfo mode = conn->modes[j]; // 匹配1920x1080@60Hz模式 if (mode.hdisplay == 1920 && mode.vdisplay == 1080 && mode.vrefresh == 60) { printf("Setting mode 1920x1080@60Hz...\n"); // 使用第一个可用的CRTC,可根据实际情况调整 set_drm_mode(drm_fd, res, conn, res->crtcs[0], &mode); break; } } }
- 重新编译运行:
gcc drm_mode_list.c -o drm_mode_set -ldrm sudo ./drm_mode_set
替代方案:使用DRM命令行工具
若不想编写C程序,可安装drm-utils工具包直接用命令行操作:
sudo apt install drm-utils
- 列出DRM资源:
sudo drm_info - 列出连接器支持的模式:
sudo modetest -c - 设置模式(替换
<connector-id>和<mode-id>为实际值):
sudo modetest -s <connector-id>:<mode-id>
内容的提问来源于stack exchange,提问作者Momoko
相关产品推荐
相关产品推荐

