DIY cloud gaming: NVIDIA and Moonlight
As you might have read from my previous post on this topic, I have a pretty neat “cloud” gaming setup running. I have one powerful desktop PC, one virtual machine with a GPU attached to it, and client machines that can be used to stream games from. To keep things simple (and because my current ISP is unbelievably bad), I have so far used streaming only over my local network.
However, there were some pretty annoying issues with this setup:
- The AMD GPU encoder is bad. 720p streaming was the best I could do if I wanted reasonable performance.
- The Windows 10 VM would sometimes not be able to start the host encoder, and the GPU drivers reported issues. This was fixed with a couple of reboots to the VM and I suspect that this may be related to the notorious GPU reset issues that AMD cards are infamous for in the VFIO world, but I wasn’t interested in digging that deep into that topic.
- The stream would sometimes randomly crash or lag. This might have been down to the AMD GPU or Parsec itself.
I read about this topic for a while and found that the overwhelming number of threads related to this topic recommend an NVIDIA GPU and Moonlight for the best streaming experience. And so I went out to get one.
It’s 2021. The world is on fire and GPU prices are insane. With that in mind, I tempered my expectations and went for something simple: a NVIDIA GTX 1060 6G by MSI. Simple, relatively modern for my games and the price was around the retail price 5 years ago (260 EUR), which is the best you can do in these lousy times.
But hey, it works! From the testing I
did in a previous post, I knew that NVIDIA had finally
stopped intentionally throwing
error code 43 in their drivers, which made this option viable. Replacing the GPU was
simple, I just had to change the PCI device ID-s according to the VFIO setup guide and changed the devices attached to
the Windows 10 VM using
virt-manager, and that was it!
Parsec: AMD vs NVIDIA
Since I was already using Parsec for my streaming purposes, I decided to do a quick test to see what the difference is between the two cards.
The previous GPU was an AMD Radeon RX 570 4GB by Sapphire. These two GPU-s are in the same performance class, which makes for a good comparison.
Here are some results taken in two quick testing sessions in Dirt Rally. Take these results with a spoonful of salt as these have not been conducted with any kind of standards. I just picked the same graphics preset, resolution and let it run with Parsec statistics view open.
AMD RX 570: 10ms
NVIDIA GTX 1060: 3ms
AMD RX 570: 8ms
NVIDIA GTX 1060: 3ms
The difference in the encode performance is huge, especially if you consider that the time between two frames is 16.6ms for a 60 FPS stream. Some of that budget is also taken up by network and decode latency in the client, so the shorter the encode time is, the better.
Parsec is fine, but I have had some trouble getting GPU-accelerated decode working on my Linux clients, and it also lacks an iOS client. While the latter isn’t a deal-breaker, the first one definitely is.
Moonlight: an open-source gem
Moonlight is an alternative to Parsec. It implements the NVIDIA GameStream protocol and has clients for most common platforms. My testing has been performed on Linux clients running Fedora 34, a Windows 10 laptop (ThinkPad X230), iPhone SE 2020 and an old Google Nexus 5. I also made an attempt to run the Moonlight client on a Raspberry Pi 1 B+, but it seems that it is simply too old for the Moonlight client, resulting in an error on startup.
To set up Moonlight, I opened up the client and tried the automatic detection over the network. Unfortunately that did not yield any results, so I input the IP address of the Windows VM manually. That worked well. This initiated a pairing process that I had to continue using Parsec, because you need to input a code on the host machine. After that, I had to quit Parsec and start streaming using Moonlight.
OK, not quite yet. Moonlight is able to detect the games installed on your system, but for a remote desktop experience, you have to do a small tweak for it to be equivalent to the experience you get from Parsec.
One thing that I noticed at the start was that the image quality on the desktop isn’t as good as on Parsec. However, it more than makes up for it in-game. Moonlight just works. There are plenty of knobs you can turn as well, including configuring the image quality by setting the resolution, framerate and network limits.
What makes Moonlight more suitable for me is that the Linux client packaged as a Flatpak is able to use the GPU for hardware-accelerated decode. The experience is great on a Linux machine and it just works, which is not something you can always expect to happen. Even an older XBOX ONE controller connected over Bluetooth works just fine over Moonlight!
The only issues that I had with Moonlight were later determined to be caused by networking issues. This shows up well on
the integrated statistics that Moonlight provides using the
Ctrl + Alt + Shift + S key combination under
Network jitter field. After stopping some services on my network, the issues went away.
The setup: one month later
After a month of use, I have made some adjustments to the setup. I used to keep the VM running so that I could just jump in and start playing whenever I liked it, but due to a tweak I made in the name of improving gaming performance, half the CPU cores on my system were not available for other purposes, such as suffering through IntelliJ indexing the project again. I decided to only power on the VM if I actually was about to take the time to play it. I haven’t yet figured out the best way to make this more convenient, though. I did make the “Calculator” key on my keyboard start/stop the VM on demand, but then GNOME started ignoring the shortcut I had setup and opened the calculator anyway, so that was a short-lived tweak.
A bigger change that I made to the setup was to store all my games on my ZFS pool that lives in another VM. For that, I setup an iSCSI target using this guide as a starting point . I used the tgt package instead. That has worked out surprisingly well, but the iSCSI target does not want to properly connect in the Windows VM on the first boot, which is mildly annoying. I soon discovered that spinning rust just does not cut it and got more SSD-based storage, otherwise other processes on the NAS could wreak havoc on the gaming experience in games like GTA V. Those issues were manifesting as long loading times and objects popping in too late, resulting in half the roads and building being missing while driving around the map. The iSCSI target solution also comes with the added bonus of having a proper backup of all my games. If Windows decides to blow itself up again and I don’t have a backup of the VM ready, then I could just reinstall it and not worry about downloading and installing all the games again.
Overall, I’m very happy about the setup. I don’t use it all too often, but occasionally launching art of rally or BeamNG.drive on any random device I own is great. I do have some concerns about the future of this setup, especially with Windows 11 having more strict system requirements and newer games demanding more performance. For the time being, this works and I intend to keep it that way.
The one box that does it all: so far so good!
If you prefer to share your thoughts on this post privately, just send me an e-mail!