Hi everyone! We’ve just shipped a really cool update to our x86/x86-64 emulation stack on Asahi Linux, and I wanted to share what we’ve been working on. As of today, non-game apps are now usable!
As you might remember from our previous blog post, Asahi Linux runs all x86/x86-64 apps in a microVM driven by muvm. How can we manage to run games in a real VM with near-native performance, without hardware GPU passthrough?
On AMD/Intel systems (and, indeed, also on macOS on Apple Silicon), GPU virtualization has always been kind of limited. Your options are to either fully pass through the hardware GPU, or use API-level GPU paravirtualization. Passing through the hardware GPU fully assigns the GPU device to the guest, which means it sees it as a “real” GPU device. This works for all guest OSes that have real drivers for that GPU, and it has native performance, but it means the GPU is dedicated to the guest, so you can’t share it with the host or integrate guest and host windows together on one screen. Meanwhile, API-level GPU paravirtualization essentially sends the OpenGL, Vulkan, or Metal commands from the guest to the host, so they are processed by the host’s GPU driver stack. This requires “generic” paravirt GPU drivers in the guest, and it is much slower than native GPU usage because all the high-level GPU drawing commands have to cross the guest-to-host barrier and be processed on the host. This is how GPU virtualization works on macOS. Some GPUs (e.g. recent Nvidia GPUs) support true sharing with hardware virtualization support, but that isn’t upstream yet and requires hardware support, which Apple GPUs don’t have.
The concept is quite simple: Instead of running the entire GPU driver stack on the guest and passing through the whole hardware GPU (no sharing), or running the entire GPU driver stack on the host and passing through high-level APIs (slow), why not split it down the middle? DRM Native Context runs the GPU kernel driver on the host, and the GPU userspace driver (Mesa) on the guest, and passes through the kernel UAPI interface from the guest to the host.