I had a really hard time getting my guest VMs to support two monitors with a resolution greater than 1080p. As it turns out, this was because the default QXL memory buffer of 16 mib isn't big enough. You probably won't run into this issue if both your monitors are only 1080p. But if they are, then need to set heads=2
AND increase the memory buffer via the vgamem
attribute (32 mib worked in my case).
On my systems, I had to to edit the libvirt XML configuration by hand to make this change. To do this, look for the vgamem
attribute. It will probably have a default value of 16384
(aka 16 mib). To increase it, to say, 32 mib, change the attribute value to 32768
. On my system, this modified XML fragment when from:
<video>
<model type="qxl" ram="65536" vram="65536" vgamem="16384" heads="1" primary="yes"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x0"/>
</video>
To:
<video>
<model type="qxl" ram="65536" vram="65536" vgamem="32768" heads="2" primary="yes"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x0"/>
</video>
If your not sure what values are actually being used, you can find out by looking at the qemu
command line parameters. On a Unix/Linux system, start the guest, and then run ps -ef | grep qemu
... and look for the QXL device. It will probably look something like -device qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,vram64_size_mb=0,vgamem_mb=32,max_outputs=2,bus=pcie.0,addr=0x1
. The vgamem_mb value of 32 is what's important.
Once you have the QXL driver setup properly, changing the guest resolution should be easy. You can use the graphical display configurator, or you can use xrandr
via the command line. In my case I chose to automate the process with the following script:
#!/bin/bash
if [ `xrandr | grep --extended-regexp --count "Virtual-0 connected|Virtual-1 connected"` == 2 ]; then
xrandr --newmode "1920x1200_60.00" 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync
xrandr --addmode Virtual-0 "1920x1200_60.00"
xrandr --addmode Virtual-1 "1920x1200_60.00"
xrandr --output Virtual-0 --mode "1920x1200_60.00" --panning 1920x1200+0+0 --output Virtual-1 --mode "1920x1200_60.00" --panning 1920x1200+1920+0
elif [ `xrandr | grep --extended-regexp --count "qxl-0 connected|qxl-1 connected"` == 2 ]; then
xrandr --newmode "1920x1200_60.00" 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync
xrandr --addmode qxl-0 "1920x1200_60.00"
xrandr --addmode qxl-1 "1920x1200_60.00"
xrandr --output qxl-0 --mode "1920x1200_60.00" --panning 1920x1200+0+0 --output qxl-1 --mode "1920x1200_60.00" --panning 1920x1200+1920+0
elif [ `xrandr | grep --extended-regexp --count "Virtual-0 connected"` == 1 ]; then
xrandr --newmode "1920x1200_60.00" 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync
xrandr --addmode Virtual-0 "1920x1200_60.00"
xrandr --output Virtual-0 --mode "1920x1200_60.00" --panning 1920x1200+0+0
else
xrandr --newmode "1920x1200_60.00" 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync
xrandr --addmode qxl-0 "1920x1200_60.00"
xrandr --output qxl-0 --mode "1920x1200_60.00" --panning 1920x1200+0+0
fi
Note this is for a 1920x1200 setup. It's also worth noting that depending on your display server, kernel version, and driver setup, etc, it's possible the display adapters will show up as either "qxl-#" or "Virtual-#".
To use the above script for a resolution other than 1920x1200, you'll need to use the appropriate modeline. To get the correct modeline, use the cvt
command line tool. As an example, if what you wanted was the modeline for a 4k (aka 2160p) monitor, you would run cvt 3840 2160 60
(assuming 60hz is the refresh rate). This would give you the modeline:
# 3840x2160 59.98 Hz (CVT 8.29M9) hsync: 134.18 kHz; pclk: 712.75 MHz
Modeline "3840x2160_60.00" 712.75 3840 4160 4576 5312 2160 2163 2168 2237 -hsync +vsync
Now the take the value which appears after "Modeline":
"3840x2160_60.00" 712.75 3840 4160 4576 5312 2160 2163 2168 2237 -hsync +vsync
And replace the value:
"1920x1200_60.00" 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync
In the example script above.
A couple of notes. Namely the text inside the quotes is actually the "label" ... so you'll need to replace the references to "1920x1200_60.00"
with the label for your new modeline. It's also worth noting that you can omit the refresh rate when calling cvt
and it will guess ... but that guess could be wrong if your running it inside the guest system. To avoid this problem, you may want to call cvt
on your host. In that case you could omit the refresh rate, and cvt
will determine the right value by looking at your hardware.