Gaming in QEMU

In the past half year I've stopped playing a lot of games I used to play because I was sick of rebooting to Windows. Although Linux gaming is doing great, for lot of players, including me, it's not there yet. So when I was bored one night during Christmas vacation I looked into virtualization and GPU passthrough. I was happy to find out that I have compatible hardware and after reading some tutorials the process seemed much simpler then I previously thought.

Basically all you need to do is add two attributes into grub entry to enable IOMMU and tell kernel to ignore the PCI-E devices that you are going to passthrough. Then install virtualization package group, setup the virtual machine in GUI and then just modify two lines in the VM configuration to trick Nvidia drivers and you are done.

Problems

Now let's talk about the problems. I will continually update this list.

  • First before you even start. Make sure you uninstalled Nvidia drivers properly before switching to different GPU otherwise your system will not start.
  • This one is not really a problem, but 3D Mark thought I was using G-Sync in the VM and was showing me warnings.
  • First game specific problem was with GTA IV, I was getting bluescreen when starting the game. It was most probably caused by SecuROM piracy protection, I fixed it by cracking the game.
  • Some games / programs may have problem if your CPU has less cores then it should have. For example if you use only 3 out of 4 cores in your VM. In this case it was H1Z1, fortunately you can start the game with parameters specifying the number of cores.
  • Then there was problem with StarCraft 2. That was solved by changing following KVM parameter before VM start. This affects more games. echo 1 > /sys/module/kvm/parameters/ignore_msrs
  • Currently I have problem with VM not starting. Sometimes it just sits there with one CPU core on 100%, I have to force-stop the machine, start it and it works again. So far I didn't find why is this happening.
Sound

I have speakers in monitor so I thought I would use the digital audio in Nvidia GPU over HDMI. That didn't work, the sound was crackling and laggy all the time. If you know how to fix this let me know. Now I am using cheap USB sound card that I passthrough to the guest. That was crackling too until I set to 16bit 48khz. So I have to manually switch the cable that goes to my speakers (not a problem when you are using cable extensions or some sort of sound mixer).

Mouse and keyboard sharing

It's not that easy as it may sound. So far I found 3 options. First, buy Synergy software for sharing mouse and keyboard between computers. I didn't test this. Second, use virtualized VGA GPU and display (s), then on host you will have window with screen as you are used to from virtualization without GPU passthrough, there will be nothing displayed but you can click on it and your mouse and keyboard will work in VM (press right CTRL to get back to host). This option has terrible latency and lags, not usable for gaming. Third option, I made mini keyboard approximately 4.5x8 cm with 5 buttons (but 2-3 buttons are enough), CTRL, F9 - F12. This is connected to host all the time and I created keyboard shortcuts for attaching and detaching mouse and keyboard with USB passthrough, this works great. Originally I wanted to do this using ATMega 328p with Arduino libraries. But it's much easier and cheaper to buy and dissect cheap keyboard (both USB and PS2 works), just connect some buttons to the PCB from keyboard and you are done.


Performance

Here is some data from benchmarks. In this test I am using only 3 out of 4 cores for the guest. So ideally the performance for multi-core stuff should be 75%. As you can see the real multi-core performance highly depends on the application. Anyway I would say the CPU and GPU performance is great.


Performance in games is hard to measure if they don't have benchmark, so take the following numbers with a grain of salt. First game I tested was Star Wars Battlefront (2015), I played the same single-player map on the same (Ultra) settings on both setups and the FPS was same - jumping between 40 - 60. I didn't see any difference in the gameplay. Next game I tried on both setups was DayZ. That was very poor choice, because FPS in this game is very unstable. I was getting 45 - 100 FPS on both setups but I would say VM had around 5 FPS less on average. I also tried Beam.NG Drive which also had around 5 FPS less and Smite in which the performance was identical on both setups. I forgot to write down the actual FPS for the last two games... Please excuse the lack of data, after the initial tests I was so excited that I immediately deleted my Windows partition.

In the next test I checked the difference between different CPU setups:
  • 1 socket, 3 cores pinned - this should be better if you plan one using host and VM system at the same time since the host has 1 core available that the VM won't touch, but host can use all 4 cores if needed
  • 1 socket, 4 cores not pinned - in this case the whole CPU is available to VM and all cores are shared between VM and host

As you can see the performance is quite similar. My assumption was mostly correct, but depends on the application  - when using both systems at the same time you will have better performance with 3 pinned cores. After longer testing I found that I rarely use both systems at the same time so I switched to the second setup which gives better performance to VM when host is not used for anything.

Scripts

Starting VM - I run this script from launcher with beesu

## windows.sh
#!/bin/bash

# Bluescreen workaround
echo 1 > /sys/module/kvm/parameters/ignore_msrs

# Change output to second screen - optional
xrandr --output HDMI2 --auto
xrandr --output HDMI1 --off

# Start VM
virsh start win10

# Wait for VM to stop
while [ "`virsh domstate win10`" != 'shut off' ]; do
  sleep 5
done

# Change output back - optional
xrandr --output HDMI2 --off
xrandr --output HDMI1 --auto

Switching input - I run those scripts using CTRL+F9 and F10 shortcuts, as described above. For this to work you have to add this sudo rule for your user: ALL=(root) NOPASSWD: /usr/bin/virsh

#!/bin/bash
# I don't want to mess with the configuration if VM is not running
if [ "`sudo virsh domstate win10`" != 'shut off' ]; then
  sudo virsh attach-device win10 /home/zbeny/Apps/windows/devices/hostdev-keyboard.xml
  sudo virsh attach-device win10 /home/zbeny/Apps/windows/devices/hostdev-mouse.xml
fi
## detach-usb.sh
#!/bin/bash
# I don't want to mess with the configuration if VM is not running
if [ "`sudo virsh domstate win10`" != 'shut off' ]; then
  sudo virsh detach-device win10 /home/zbeny/Apps/windows/devices/hostdev-keyboard.xml
  sudo virsh detach-device win10 /home/zbeny/Apps/windows/devices/hostdev-mouse.xml
fi
<hostdev mode='subsystem' type='usb'>
  <source>
    <vendor id='0x195d'/>
    <product id='0x2030'/>
  </source>
</hostdev>

You will find more information about usb "hotplugging" here: http://rolandtapken.de/blog/2011-04/how-auto-hotplug-usb-devices-libvirt-vms-update-1

Links