You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的简化示例:

  1. 在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;
}
  1. 在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;
        }
    }
}
  1. 重新编译运行:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 04:07:21