[pve-devel] [PATCH qemu-server 1/1 v2] fix #1952: make vga memory configurable

Dominik Csapak d.csapak at proxmox.com
Fri Nov 9 13:31:09 CET 2018


we change 'vga' to a property string and add a 'memory' property
with this, the user can better control the memory given to the virtual
gpu, this is especially useful for spice/qxl since high resolutions need
more memory

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 PVE/QemuServer.pm     | 134 ++++++++++++++++++++++++++++++++++++++++----------
 PVE/QemuServer/PCI.pm |   3 +-
 2 files changed, 109 insertions(+), 28 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 82c9b96..c3932d0 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -223,6 +223,24 @@ my $agent_fmt = {
     },
 };
 
+my $vga_fmt = {
+    type => {
+	description => "Select the VGA type.",
+	type => 'string',
+	default => 'std',
+	optional => 1,
+	default_key => 1,
+	enum => [qw(cirrus qxl qxl2 qxl3 qxl4 serial0 serial1 serial2 serial3 std virtio vmware)],
+    },
+    memory => {
+	description => "Sets the VGA memory (in MiB). Has no effect with serial display.",
+	type => 'integer',
+	optional => 1,
+	minimum => 4,
+	maximum => 512,
+    },
+};
+
 my $confdesc = {
     onboot => {
 	optional => 1,
@@ -431,17 +449,16 @@ EODESC
     },
     vga => {
 	optional => 1,
-	type => 'string',
-	description => "Select the VGA type.",
-        verbose_description => "Select the VGA type. If you want to use high resolution" .
-	    " modes (>= 1280x1024x16) then you should use the options " .
-	    "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
-	    "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
-	    "display sever. For win* OS you can select how many independent " .
-	    "displays you want, Linux guests can add displays them self. " .
-	    "You can also run without any graphic card, using a serial device" .
-	    " as terminal.",
-	enum => [qw(cirrus qxl qxl2 qxl3 qxl4 serial0 serial1 serial2 serial3 std virtio vmware)],
+	type => 'string', format => $vga_fmt,
+	description => "Configure the VGA hardware.",
+	verbose_description => "Configure the VGA Hardware. If you want to use ".
+	    "high resolution modes (>= 1280x1024x16) you may need to increase " .
+	    "the vga memory option. Since QEMU 2.9 the default VGA display type " .
+	    "is 'std' for all OS types besides some Windows versions (XP and " .
+	    "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
+	    "display server. For win* OS you can select how many independent " .
+	    "displays you want, Linux guests can add displays them self.\n".
+	    "You can also run without any graphic card, using a serial device as terminal.",
     },
     watchdog => {
 	optional => 1,
@@ -1961,6 +1978,54 @@ sub print_cpu_device {
     return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
 }
 
+my $vga_map = {
+    'cirrus' => 'cirrus-vga',
+    'std' => 'VGA',
+    'vmware' => 'vmware-svga',
+    'virtio' => 'virtio-vga',
+};
+
+sub print_vga_device {
+    my ($conf, $vga, $id, $qxlnum, $bridges) = @_;
+
+    my $type = $vga_map->{$vga->{type}};
+    my $vgamem_mb = $vga->{memory};
+    if ($qxlnum) {
+	$type = $id ? 'qxl' : 'qxl-vga';
+    }
+    die "no devicetype for $vga->{type}\n" if !$type;
+
+    my $memory = "";
+    if ($vgamem_mb) {
+	if ($vga->{type} eq 'virtio') {
+	    my $bytes = PVE::Tools::convert_size($vgamem_mb, "mb" => "b");
+	    $memory = ",max_hostmem=$bytes";
+	} elsif ($qxlnum) {
+	    # from https://www.spice-space.org/multiple-monitors.html
+	    $memory = ",vgamem_mb=$vga->{memory}";
+	    my $ram = $vgamem_mb * 4;
+	    my $vram = $vgamem_mb * 2;
+	    $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
+	} else {
+	    $memory = ",vgamem_mb=$vga->{memory}";
+	}
+    } elsif ($qxlnum && $id) {
+	$memory = ",ram_size=67108864,vram_size=33554432";
+    }
+
+    my $q35 = machine_type_is_q35($conf);
+    my $vgaid = "vga" . ($id // '');
+    my $pciaddr;
+    if ($q35 && $vgaid eq 'vga') {
+	# on is on the pcie.0 bus on q35
+	$pciaddr = print_pcie_addr($vgaid, $bridges);
+    } else {
+	$pciaddr = print_pci_addr($vgaid, $bridges);
+    }
+
+    return "$type,id=${vgaid}${memory}${pciaddr}";
+}
+
 sub drive_is_cloudinit {
     my ($drive) = @_;
     return $drive->{file} =~ m@[:/]vm-\d+-cloudinit(?:\.$QEMU_FORMAT_RE)?$@;
@@ -2286,6 +2351,15 @@ sub parse_guest_agent {
     return $res;
 }
 
+sub parse_vga {
+    my ($value) = @_;
+
+    return {} if !$value;
+    my $res = eval { PVE::JSONSchema::parse_property_string($vga_fmt, $value) };
+    warn $@ if $@;
+    return $res;
+}
+
 PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
 sub verify_usb_device {
     my ($value, $noerr) = @_;
@@ -3167,7 +3241,9 @@ sub conf_has_serial {
 sub vga_conf_has_spice {
     my ($vga) = @_;
 
-    return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
+    my $vgaconf = parse_vga($vga);
+    my $vgatype = $vgaconf->{type};
+    return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
 
     return $1 || 1;
 }
@@ -3277,16 +3353,16 @@ sub config_to_command {
     # add usb controllers
     my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers($conf, $bridges, $q35, $usbdesc->{format}, $MAX_USB_DEVICES);
     push @$devices, @usbcontrollers if @usbcontrollers;
-    my $vga = $conf->{vga};
+    my $vga = parse_vga($conf->{vga});
 
-    my $qxlnum = vga_conf_has_spice($vga);
-    $vga = 'qxl' if $qxlnum;
+    my $qxlnum = vga_conf_has_spice($conf->{vga});
+    $vga->{type} = 'qxl' if $qxlnum;
 
-    if (!$vga) {
+    if (!$vga->{type}) {
 	if (qemu_machine_feature_enabled($machine_type, $kvmver, 2, 9)) {
-	    $vga = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
+	    $vga->{type} = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
 	} else {
-	    $vga = ($winversion >= 6) ? 'std' : 'cirrus';
+	    $vga->{type} = ($winversion >= 6) ? 'std' : 'cirrus';
 	}
     }
 
@@ -3297,7 +3373,7 @@ sub config_to_command {
     } else {
 	$tablet = $defaults->{tablet};
 	$tablet = 0 if $qxlnum; # disable for spice because it is not needed
-	$tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
+	$tablet = 0 if $vga->{type} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
     }
 
     push @$devices, '-device', print_tabletdevice_full($conf) if $tablet;
@@ -3325,7 +3401,7 @@ sub config_to_command {
 	if ($d->{'x-vga'}) {
 	    $xvga = ',x-vga=on';
 	    $kvm_off = 1;
-	    $vga = 'none';
+	    $vga->{type} = 'none';
 	    $gpu_passthrough = 1;
 
 	    if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
@@ -3428,12 +3504,12 @@ sub config_to_command {
 
     push @$cmd, '-no-reboot' if  defined($conf->{reboot}) && $conf->{reboot} == 0;
 
-    push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
-
-    if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
+    if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga ne 'none'){
+	push @$devices, '-device', print_vga_device($conf, $vga, undef, $qxlnum, $bridges);
 	my $socket = vnc_socket($vmid);
 	push @$cmd,  '-vnc', "unix:$socket,x509,password";
     } else {
+	push @$cmd, '-vga', 'none' if $vga->{type} eq 'none';
 	push @$cmd, '-nographic';
     }
 
@@ -3540,13 +3616,17 @@ sub config_to_command {
 	if ($qxlnum > 1) {
 	    if ($winversion){
 		for(my $i = 1; $i < $qxlnum; $i++){
-		    my $pciaddr = print_pci_addr("vga$i", $bridges);
-		    push @$devices, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
+		    push @$devices, '-device', print_vga_device($conf, $vga, $i, $qxlnum, $bridges);
 		}
 	    } else {
 		# assume other OS works like Linux
-		push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
-		push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
+		my ($ram, $vram) = ("134217728", "67108864");
+		if ($vga->{memory}) {
+		    $ram = PVE::Tools::convert_size($qxlnum*4*$vga->{memory}, 'mb' => 'b');
+		    $vram = PVE::Tools::convert_size($qxlnum*2*$vga->{memory}, 'mb' => 'b');
+		}
+		push @$cmd, '-global', "qxl-vga.ram_size=$ram";
+		push @$cmd, '-global', "qxl-vga.vram_size=$vram";
 	    }
 	}
 
diff --git a/PVE/QemuServer/PCI.pm b/PVE/QemuServer/PCI.pm
index 0d9cf24..5ddda4f 100644
--- a/PVE/QemuServer/PCI.pm
+++ b/PVE/QemuServer/PCI.pm
@@ -9,7 +9,7 @@ print_pcie_addr
 
 my $devices = {
     piix3 => { bus => 0, addr => 1 },
-    #addr2 : first videocard
+    vga => { bus => 0, addr => 2 },
     balloon0 => { bus => 0, addr => 3 },
     watchdog => { bus => 0, addr => 4 },
     scsihw0 => { bus => 0, addr => 5 },
@@ -130,6 +130,7 @@ sub print_pcie_addr {
 
     my $res = '';
     my $devices = {
+	vga => { bus => 'pcie.0', addr => 1 },
 	hostpci0 => { bus => "ich9-pcie-port-1", addr => 0 },
 	hostpci1 => { bus => "ich9-pcie-port-2", addr => 0 },
 	hostpci2 => { bus => "ich9-pcie-port-3", addr => 0 },
-- 
2.11.0





More information about the pve-devel mailing list