Skip to content

Instantly share code, notes, and snippets.

@peppergrayxyz
Last active June 9, 2025 18:42
Show Gist options
  • Save peppergrayxyz/fdc9042760273d137dddd3e97034385f to your computer and use it in GitHub Desktop.
Save peppergrayxyz/fdc9042760273d137dddd3e97034385f to your computer and use it in GitHub Desktop.
QEMU with VirtIO GPU Vulkan Support

QEMU with VirtIO GPU Vulkan Support

With its latest reales qemu added the Venus patches so that virtio-gpu now support venus encapsulation for vulkan. This is one more piece to the puzzle towards full Vulkan support.

An outdated blog post on clollabora described in 2021 how to enable 3D acceleration of Vulkan applications in QEMU through the Venus experimental Vulkan driver for VirtIO-GPU with a local development environment. Following up on the outdated write up, this is how its done today.

Definitions

Let's start with the brief description of the projects mentioned in the post & extend them:

  • QEMU is a machine emulator
  • VirGL is an OpenGL driver for VirtIO-GPU, available in Mesa.
  • Venus is an experimental Vulkan driver for VirtIO-GPU, also available in Mesa.
  • Virglrenderer is a library that enables hardware acceleration to VM guests, effectively translating commands from the two drivers just mentioned to either OpenGL or Vulkan.
  • libvirt is an API for managing platform virtualization
  • virt-manager is a desktop user interface for managing virtual machines through libvirt

Merged Patches:

Work in progress:

Prerequisites

Make sure you have the proper version installed on the host:

  • linux kernel >= 6.13 built with CONFIG_UDMABUF
  • working Vulkan and kvm setup
  • qemu >= 9.2.0
  • virglrenderer with enabled venus support
  • mesa >= 24.2.0

You can verify this like so:

$ uname -r
6.13.0
$ ls /dev/udmabuf
/dev/udmabuf
$ ls /dev/kvm
/dev/kvm
$ qemu-system-x86_64 --version
QEMU emulator version 9.2.0
Copyright (c) 2003-2024 Fabrice Bellard and the QEMU Project developers

Check your distros package sources how they build virglrenderer.

For Vulkan to work you need the proper drivers to be installed for your graphics card.

To verfiy your setup, install vulkan-tools. Make sure mesa >= 24.2.0 and test vkcube:

$ vulkaninfo --summary | grep driverInfo
	driverInfo         = Mesa 24.2.3-1ubuntu1
	driverInfo         = Mesa 24.2.3-1ubuntu1 (LLVM 19.1.0)
...
$ vkcube
Selected GPU x: ..., type: ...

Building qemu

If your distro doesn't (yet) ship and updated version of qemu, you can build it yourself from source:

wget https://download.qemu.org/qemu-9.2.0.tar.xz
tar xvJf qemu-9.2.0.tar.xz
cd qemu-9.2.0
mkdir build && cd build
../configure --target-list=x86_64-softmmu  \
  --enable-kvm                 \
  --enable-opengl              \
  --enable-virglrenderer       \
  --enable-gtk                 \
  --enable-sdl
make -j4

The configuration step will throgh errors if packages are missing. Check the qemu wiki for further info what to install: https://wiki.qemu.org/Hosts/Linux

Create and run an image for QEMU

Create an image & fetch the distro of your choice:

Host

ISO=ubuntu-24.10-desktop-amd64.iso  
wget https://releases.ubuntu.com/oracular/ubuntu-24.10-desktop-amd64.iso  

IMG=ubuntu-24-10.qcow2
qemu-img create -f qcow2 $IMG 16G

Run a live version or install the distro

qemu-system-x86_64                                               \
    -enable-kvm                                                  \
    -M q35                                                       \
    -smp 4                                                       \
    -m 4G                                                        \
    -cpu host                                                    \
    -net nic,model=virtio                                        \
    -net user,hostfwd=tcp::2222-:22                              \
    -device virtio-vga-gl,hostmem=4G,blob=true,venus=true        \
    -vga none                                                    \
    -display gtk,gl=on,show-cursor=on                            \
    -usb -device usb-tablet                                      \
    -object memory-backend-memfd,id=mem1,size=4G                 \
    -machine memory-backend=mem1                                 \
    -hda $IMG                                                    \
    -cdrom $ISO                                                  

Adjust the parameters accordingly:

  • smp: number of cpu cores
  • m: RAM
  • hostmem,size: VRAM

Guest

Install mesa-utilites and vulkan-tools to test the setup:

$ glxinfo -B
$ vkcube
Selected GPU x: ..., type: ...

If the deive is llvmpipe somehting is wrong. The device should be virgl (...).

Troubleshooting

  • (host) add -d guest_errors to show error messages from the guest
  • (guest) try installing vulkan virtio drivers and mesa
  • check the original blog post

Ubuntu 24.10

This is how you do it on Ubuntu

kernel

Install mainline: https://github.com/bkw777/mainline

sudo add-apt-repository ppa:cappelikan/ppa
sudo apt update
sudo apt install mainline

find the latest kernel (>= 6.13), at the time of writing 6.13 is a release candidate, so include those:

$ mainline check --include-rc

Install kernel:

$ sudo mainline install 6.13-rc1

Verfify installed kernels:

$ mainline list-installed
mainline 1.4.10
Installed Kernels:
linux-image-6.11.0-13-generic
linux-image-generic-hwe-24.04
linux-image-unsigned-6.13.0-061300rc1-generic
mainline: done

reboot into new kernel

verify running kernel

$ uname -r
6.13.0-061300rc1-generic

virglrenderer

the ubuntu package is not compiled with the proper flags.

If installed remove it: $ sudo apt-get remove libvirglrenderer-dev

download, build & install from source with venus enabled

wget    https://gitlab.freedesktop.org/virgl/virglrenderer/-/archive/1.1.0/virglrenderer-1.1.0.tar.gz
sudo apt-get install python3-full ninja-build libvulkan-dev libva-dev
python3 -m venv venv
venv/bin/pip install meson
venv/bin/meson build -Dvideo=true -Dvenus=true
ninja -C build
ninja install

qemu

install qemu >= 9.2.0, at the time of writing ubuntu has not yet packaged it

Install build depdencies: https://wiki.qemu.org/Hosts/Linux

sudo apt-get install build-essential pip libslirp-dev slirp
sudo apt-get install git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build
sudo apt-get install git-email
sudo apt-get install libaio-dev libbluetooth-dev libcapstone-dev libbrlapi-dev libbz2-dev
sudo apt-get install libcap-ng-dev libcurl4-gnutls-dev libgtk-3-dev
sudo apt-get install libibverbs-dev libjpeg8-dev libncurses5-dev libnuma-dev
sudo apt-get install librbd-dev librdmacm-dev
sudo apt-get install libsasl2-dev libsdl2-dev libseccomp-dev libsnappy-dev libssh-dev
sudo apt-get install libvde-dev libvdeplug-dev libvte-2.91-dev libxen-dev liblzo2-dev
sudo apt-get install valgrind xfslibs-dev 
sudo apt-get install libnfs-dev libiscsi-dev

build and run as described

virt-manager

-- work in progress --

Currently this is work in progress, so there is no option to add vulkan support in virt-manager. There are no fields to configure this. Also xml doesnt work, because libvirt doesn't know about these options either, so xml validation fails. There is however an option for QEMU command-line passthrough which bypasses the validation.

If you setup a default machine with 4G of memory, you can do this:

  <qemu:commandline>
    <qemu:arg value="-device"/>
    <qemu:arg value="virtio-vga-gl,hostmem=4G,blob=true,venus=true"/>
    <qemu:arg value="-object"/>
    <qemu:arg value="memory-backend-memfd,id=mem1,size=4G"/>
    <qemu:arg value="-machine"/>
    <qemu:arg value="memory-backend=mem1"/>
    <qemu:arg value="-vga"/>
    <qemu:arg value="none"/>
  </qemu:commandline>

Which gives this error:

qemu-system-x86_64: virgl could not be initialized: -1

Changing the number from 4G to 4194304k (same as memory) leds to this error:

qemu-system-x86_64: Spice: ../spice-0.15.2/server/red-qxl.cpp:435:spice_qxl_gl_scanout: condition `qxl_state->gl_draw_cookie == GL_DRAW_COOKIE_INVALID' failed

to be further investigated.

@zhangyiwei
Copy link

The other issue with the VM screen saver being a problem, once it gets activated, my GPU starts also to work much more... its usage raising from 15 to 70% for "graphics pipe" according to radeontop.

Pretty swamped with other bits at the moment, but I'll take a look later when I have time. The screen saver UI rendering there is likely done with Virgl, but I don't think it's Virgl's issue since it only renders per requested like any other gl driver. It could be possible that vsync has been disabled by then but the render loop hasn't been paused earlier, so that the display manager allows the desktop session to render like a beast..

@bk4nt
Copy link

bk4nt commented May 28, 2025

Steps to reproduce...

  • start the VM, connect to the console using KVM/VMM, start vkcube, all is fine,
  • lock the X session in that console, I'm using XFCE4 in that VM,
  • the VM console shows "display output is not active" in white on a black screen, host CPU/GPU fan spins up,
  • a second later, the lock/login screen is shown; CPU/GPU usage still is high, stays high
  • VM CPU/GPU usage started to raise, host CPU/GPU fan spinned up,

In the journal of the VM, I do notice:

May 29 00:20:32 trixie-gl spice-vdagentd[3826]: Error getting active session: No data available
May 29 00:20:32 trixie-gl spice-vdagentd[3826]: Error getting active session: No data available
May 29 00:20:32 trixie-gl spice-vdagentd[3826]: closed vdagent virtio channel

If I reconnect to the console, and only if I do, the CPU/GPU usage lowers again.

Following this, after reconnecting to the console, VM and CPU/GPU usage being fine again, if I do close the VM/VMM console, I do later notice following events in the VM journal, and the CPU/GPU loads raise again:

May 29 00:32:49 trixie-gl spice-vdagent[3801]: display: failed to call GetCurrentState from mutter over DBUS
May 29 00:32:49 trixie-gl spice-vdagent[3801]:    error message: Cannot invoke method; proxy is for the well-known name org.gnome.Mutter.DisplayConfig without an owner, and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag
May 29 00:32:49 trixie-gl spice-vdagentd[3826]: Set max clipboard: 104857600
May 29 00:32:49 trixie-gl spice-vdagent[3801]: vdagent_audio_playback_sync mute=no nchannels=2
May 29 00:32:49 trixie-gl spice-vdagent[3801]: vdagent-audio: (playback-left) 65535 (100.00%)
May 29 00:32:49 trixie-gl spice-vdagent[3801]: vdagent-audio: (playback-right) 65535 (100.00%)
May 29 00:32:49 trixie-gl spice-vdagent[3801]: vdagent_audio_record_sync mute=no nchannels=2
May 29 00:32:49 trixie-gl spice-vdagent[3801]: vdagent-audio: (capture-left) 65535 (100.00%)
May 29 00:32:49 trixie-gl spice-vdagent[3801]: vdagent-audio: (capture-right) 65535 (100.00%)
May 29 00:43:46 trixie-gl spice-vdagentd[3826]: Error getting active session: No data available
May 29 00:43:46 trixie-gl spice-vdagentd[3826]: Error getting active session: No data available
May 29 00:43:46 trixie-gl spice-vdagentd[3826]: closed vdagent virtio channel

In that state, either I need to reconnect/log in again using VMM, or I do need to shutdown the VM to recover normal CPU/GPU usage.

@bk4nt
Copy link

bk4nt commented May 30, 2025

So far, I do not understand what could be wrong with x2go and VirtualGL. I still use KVM/libvirtd without any sec stuff.

I do not know how VNC servers/clients supporting VirtualGL (http://virtualgl.org) might work (TurboVNC, ...).

This is from the console, via an IP KVM, all is working as expected, sharing the same host GPU:

  • vkcube on the host is fine
  • vkcube inside the trixie-gl VM and via KVM/VMM console is fine also

image

Following is when I connect to the host via x2go and using VirtuaGL, for GLX in that session:

  • the host is named elen, the VM still is exact the same, trixie-gl,
  • inside the elen x2go session, SDR++ (needing OpenGL) could work fine with the vglrun VirtualGL wrapper,
  • but vkcube doesn't work, it should maybe with the vglrun wrapper provided by VirtualGL
  • inside this x2go session, the KVM/VMM console of trixie-gl is always black (I need to admin it via the host console / IP KVM)
  • on the host, SDR++ is now dead, starts fine but quickly stops to work, its app freezes...

image

I've now restarted the host. SDR++ was since days working fine inside x2go using VirtualGL... Today, it starts, then freezes (but this might be related to audio, not GLX; other apps like VLC now ended silenced also):

image

At some point, I will have to reformat that host. I had tweaked too much since I installed it, some 3 weeks ago. Too much host tweaks is what I would like to avoid by using KVM/QEMU and VMs. Its much easier to reuse qcow2 images or to reinstall only VMs...

But its very promising. All this being work in progress; I shall maybe use the latest software versions for the main I do use.

I added x2go and VirtualGL inside the trixie-gl VM. There inside, vkcube fails to start; this may need tweaks. But glxgears seems to run using the host GPU:

image

image

image

Instead of fixing this host (to be reformated later), I'll focus an try to use SDR++ inside that Trixie VM.. Should work fine as glxinfo/glxgears run. Later I'll keep the VM qcow2/XML.

Edit...

I now have SDR++ running inside the Trixie VM. Using VirtualGL and x2go. That way, the sound (via x2go) is fine again. But the GLX seems rendered by a mix of host GPU and the CPUs... that may change over the next months or using latest software versions.

image

@zhando
Copy link

zhando commented Jun 4, 2025

Hello. I went down this qemu/venus/vulkan etc rabbit hole looking for a better experience with a qemu guest running gnome desktop and arch linux. Tried qxl/spice/vdagent. Works (kind of) but there had to be something better. And that better had to be paravirtualized gpu - most reasonable path seemed to me. No end of frustration with my desktop machine with Ryzen cpu and Nvidia 3060ti using the approach in this gist. Got a blank screen using gtk,gl=on. Got something with sdl and the display is accelerated but is pretty unstable. Runs glxgears ok but can't run vkcube to save its life.

What made all the difference to me is the host. I moved everything to my old Dell Intel i5 laptop with Intel UHD graphics. Everything.just.works. Crisp display on the guest. Stable, usable. vkcube runs, a bit jittery, but I don't care - I just wanted a reasonable desktop gui for arch linux in a qemu guest.

I'm still down for making my Ryzen/Nvidia desktop work. Should I attempt https://gist.github.com/peppergrayxyz/fdc9042760273d137dddd3e97034385f?permalink_comment_id=5589674#gistcomment-5589674 this checklist from @myrslint and the followup patches from @zhangyiwei?

Note: I use arch linux on all my hosts.

@zhangyiwei
Copy link

Hi @zhando, for your Ryzen/Nvidia setup, at least don't need to patch your host kernel as long as that's new enough (on recent 6.13 release or 6.14+). The (1) in the linked comment is specifically for Intel EPT. For virglrenderer, you can use the stock version as well.

First of all, does this MESA_VK_WSI_DEBUG=sw vkcube work via venus on your NV dGPU card? If it works, it's then up to you whether taking the trouble to do below further patches, or just live with the suboptimal wsi code patch and wait till everything's in place.

Patches needed for correctness:

@zhando
Copy link

zhando commented Jun 4, 2025

Hello @zhangyiwei ,

Thank you so much for your very quick reply. I just tried your suggestion for vkcube in the guest (sdl display) and I can barely believe it worked. Yes, to be clear, it worked.

I'm inclined to try your patches, if it means the gtk display works (as it does unpatched on my ancient laptop) and the guest gui (gnome desktop under arch linux) becomes stable.

Can't hurt to try. Thanks so much to you and the rest of the participants here for all the hard work.

@zhando
Copy link

zhando commented Jun 5, 2025

Hi @zhangyiwei,

Ok the patch to qemu went smoothly. Applied to my host.

The patches to mesa are a bit more problematic. There are two of them. The good news is the first patch has landed in mesa-25.1.2-2 (arch packaging). The arch linux archive currently marks that package rev as being in testing. I just grabbed the PKGBUILD and built it and installed it in my guest. I believe it helps the overall stability (w/ sdl) but vkcube w/o the env var setting still locks up the gui and gtk,gl=on still produces a blank screen.

I tried to strong arm the second patch into wsi_common.c and wsi_common_private.h but wsi_common.c has changed a lot since you first submitted the patch. I got lost and paused. I think I saw something happening in main with this second patch but I'm wedded to working through arch linux packaging. So I'll wait until it's sorted out.

Thanks again.

@zhangyiwei
Copy link

Hello @zhangyiwei ,

Thank you so much for your very quick reply. I just tried your suggestion for vkcube in the guest (sdl display) and I can barely believe it worked. Yes, to be clear, it worked.

Thanks for confirming this! I've landed the venus workaround to force sw wsi path with nv proprietary, and is going to backport it to 25.1 release.

Meanwhile, the underlying brokeness is on NV's plate:

  1. https://gitlab.freedesktop.org/virgl/virglrenderer/-/issues/602#note_2946860
  2. https://gitlab.freedesktop.org/mesa/mesa/-/issues/13331

Will follow up to drop the workaround against the proper nv driver version once there's a fix there. Thanks for bearing with me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment