起因背景

我们在使用NVIDIA vGPU切分显卡资源给虚拟机后,这台虚拟机就会存在2个虚拟屏幕,一个是PVE的VNC窗口,一个是NVIDIA VGX虚拟屏幕,当我们在PVE的VNC窗口操作虚拟机的话,部分应用又无法调用到GPU资源,把VNC窗口设置“无”即NONE的话只能借助外部远程工具连接虚拟机,PVE的VNC窗口又不工作。

所以这里参考佛西:为vgpu设备添加mdev gpu类型的补丁给PVE9打上。让VNC窗口直接输出vGPU显卡画面。

支持类型

说明版本
系统PVE 9.1.6
内核Linux pve9 6.17.13-2-pve
pve-qemu-kvm10.0.2-7
支持的虚拟机SeaBIOS/OVMF
正常工作版本vGPU16/17/18
不工作版本vGPU19

修改QemuServer.pm

可以使用nano命令来编辑QemuServer.pm文件
nano /usr/share/perl5/PVE/QemuServer.pm
1)第一处,在这句结尾加入mdev参数

        enum => [
-            qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio virtio-gl vmware)
        ],

修改完成后效果:

        enum => [
+            qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio virtio-gl vmware mdev)
        ],

2)第二处,在这句结尾加入'mdev' => 'mdev',参数

my $vga_map = {
    'cirrus' => 'cirrus-vga',
    'std' => 'VGA',
    'vmware' => 'vmware-svga',
    'virtio' => 'virtio-vga',
    'virtio-gl' => 'virtio-vga-gl',
};

修改完成后效果:

my $vga_map = {
    'cirrus' => 'cirrus-vga',
    'std' => 'VGA',
    'vmware' => 'vmware-svga',
    'virtio' => 'virtio-vga',
    'virtio-gl' => 'virtio-vga-gl',
+    'mdev' => 'mdev',
};

3)第三处,在这句中加入if ($vga->{type} ne 'mdev'){ if判断语句,别忘了后面还有个括号}参数

push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
    if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none') {
    push @$devices, '-device',
        print_vga_device($conf, $vga, $arch, $machine_version, undef, $qxlnum, $bridges);
    push @$cmd, '-display', 'egl-headless,gl=core' if $vga->{type} eq 'virtio-gl'; # VIRGL

修改完成后效果:

push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
    if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none') {
+    if ($vga->{type} ne 'mdev'){
    push @$devices, '-device',
        print_vga_device($conf, $vga, $arch, $machine_version, undef, $qxlnum, $bridges);
+    }
    push @$cmd, '-display', 'egl-headless,gl=core' if $vga->{type} eq 'virtio-gl'; # VIRGL

4)第四处,在这句结尾加入|mdev参数,让Mdev显示器支持spcie协议,如果要用SPICE协议云桌面办公的建议加上(可选)

   my $spice_port;

    assert_clipboard_config($vga);
-    my $is_spice = $qxlnum || $vga->{type} =~ /^virtio/;

修改完成后效果:

   my $spice_port;

    assert_clipboard_config($vga);
+    my $is_spice = $qxlnum || $vga->{type} =~ /^(virtio|mdev)/;

修改PCI.pm

可以使用nano命令来编辑PCI.pm文件
nano /usr/share/perl5/PVE/QemuServer/PCI.pm
1)第一处,在这2句中间加入mdev类型的判断处理

            my $mf_addr = $multifunction ? ".$j" : '';
            $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";

            if ($j == 0) {
                $devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar};
                $devicestr .= "$xvga";

修改完成后效果:

            my $mf_addr = $multifunction ? ".$j" : '';
            $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";

+        my $mdevtype = $d->{mdev} // undef;
+        if ($mdevtype =~ /^(.*?)-/) {
+            $mdevtype = $1;
+        }

            if ($j == 0) {
                $devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar};
                $devicestr .= "$xvga";

2)第二处,在这2句中间加入mdev类型的判断处理

            if ($j == 0) {
                $devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar};
                $devicestr .= "$xvga";
                $devicestr .= ",multifunction=on" if $multifunction;
                $devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile};
                $devicestr .= ",bootindex=$bootorder->{$id}" if $bootorder->{$id};
                for my $option (qw(vendor-id device-id sub-vendor-id sub-device-id)) {
                    $devicestr .= ",x-pci-$option=$d->{$option}" if $d->{$option};
                }
            }      
            push @$devices, '-device', $devicestr;
            last if $d->{mdev};
        }
    }

修改完成后效果:

            if ($j == 0) {
                $devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar};
                $devicestr .= "$xvga";
                $devicestr .= ",multifunction=on" if $multifunction;
                $devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile};
                $devicestr .= ",bootindex=$bootorder->{$id}" if $bootorder->{$id};
                for my $option (qw(vendor-id device-id sub-vendor-id sub-device-id)) {
                    $devicestr .= ",x-pci-$option=$d->{$option}" if $d->{$option};
                }
            }
+        if ($mdevtype && $vga->{type} eq 'mdev'){
+            $devicestr .= ",display=on,ramfb=on,driver=vfio-pci-nohotplug";
+        }
            push @$devices, '-device', $devicestr;
            last if $d->{mdev};
        }
    }

修改pvemanagerlib.js

可以使用nano命令来编辑pvemanagerlib.js文件
nano /usr/share/pve-manager/js/pvemanagerlib.js
修改前端文件,在这句结尾加入mdev: 'NVIDIA vGPU',参数

std: gettext('Standard VGA'),
            vmware: gettext('VMware compatible'),
            qxl: 'SPICE',
            qxl2: 'SPICE dual monitor',
            qxl3: 'SPICE three monitors',
            qxl4: 'SPICE four monitors',
            serial0: gettext('Serial terminal') + ' 0',
            serial1: gettext('Serial terminal') + ' 1',
            serial2: gettext('Serial terminal') + ' 2',
            serial3: gettext('Serial terminal') + ' 3',
            virtio: 'VirtIO-GPU',
            'virtio-gl': 'VirGL GPU',
+            mdev: 'NVIDIA vGPU',
            none: Proxmox.Utils.noneText,
        },

重启服务让其生效,重启完记得Ctrl+F5清理下浏览器缓存。

systemctl restart pveproxy
systemctl restart pvedaemon

最后就是给虚拟机添加上vGPU设备了,然后在显示那选择NVIDIA vGPU显示就能正常输入vGPU画面了。只测试了vGPU16 17 18的驱动版本可以正常显示,vGPU19 黑屏异常可能驱动版本过高导致。

广告:PROXMOX-VE 技术支持,疑难解答,有需要可以闲鱼与我联系↓↓↓

PVE技术支持
最后修改:2026 年 04 月 01 日
如果觉得我的文章对你有用,请随意赞赏