This article explains how to enable VirtIO-GPU Venus on QEMU, which is now having venus=on
option support from v9.2.0 (released Nov. 2024). On top of it, I will show some benchmark results and compare it with VirGL solution.
Introduction
Official documentation of Virtio-GPU Venus is here. As explained on this article, Venus, as the code name of virtual Vulkan driver, is a relatively new solution to use host GPU through Virtual machine. Though this Venus articles was written in 2021 and development on QEMU seemed to be conducted on QEMU, its support on QEMU hasn't been upstreamed for long time. At the end of last year (2024), QEMU finally merged venus support at v9.2.0. Now everyone can try this solution without any patch-set to QEMU. By using v9.2.0+, just adding -device virtio-vga-gl,blob=on,hostmem=4G,venus=on
will enable us to use virtual Vulkan driver. More detailed procedure will be shown on this paper.
Prerequisite
- Ubuntu with docker installed.
- YoctoLinux build environment.
- x86_64 machine (if using my prebuilt core-image-weston-rootfs.ext4)
Everything necessary below will be built from source code.
- Qemu v9.2.0
- Mesa 24.0.1
- Virglrenderer 1.1.0
- bzImage(Linux kernel) 5.16+
Essentially only what we need to have is docker. Yocto Linux environment is nice to have if you want to modify guest machine component: Mesa version and so on.
The version combination of Mesa 24.0.1 / Virglrenderer 1.1.0 doesn't mean starting version of Venus support. It's just an version I verified. The exact support status can essentially varies for each combination of mesa/virglrenderer. We can't say simply which version of mesa/virglrenderer will gracefully support venus.
Build instructions
It's often the case that OSS software has many compile time options. Some of these are automatically detected at configure script depending on installed libraries. Qemu, VirGL, Mesa, all of these have this mechanism. Only way to precisely select desired option for each component is to make your own binary from source code. Here, I show how to make these component by using Docker Ubuntu environment.
1. QEMU with VirGL renderer
The key option is '-Dvenus=true' for virglrenderer. Qemu configure script will automatically detect platform installed virglrenderer without any option. DO NOT install virglrenderer from apt install
command to make sure that qemu can detect locally built virglrenderer. I prepared just-use-this Dockerfile as below:
FROM ubuntu:22.04
RUN apt update && apt install -y tzdata
RUN apt update && apt install -y \
bison clang cmake device-tree-compiler flex git iasl libaio-dev libbluetooth-dev libbpfcc-dev \
libbpf-dev libbrlapi-dev libbz2-dev libcacard-dev libcap-ng-dev libcapstone-dev libcbor-dev \
libcurl4-gnutls-dev libdaxctl-dev libdwarf-dev libdw-dev libfdt-dev libfuse3-dev libglib2.0-dev \
libgstreamer1.0-dev libgstreamer-plugins-bad1.0-dev libgstreamer-plugins-base1.0-dev \
libgstreamer-plugins-good1.0-dev libgtk-3-dev libgvnc-1.0-dev libibverbs-dev libiscsi-dev \
libjack-dev libjpeg8-dev libkeyutils-dev liblzo2-dev libncurses5-dev libnfs-dev libnuma-dev \
libpixman-1-dev libpmem2-dev libpmemblk-dev libpmem-dev libpmemkv-dev libpmemlog-dev libpmemobj-cpp-dev \
libpmemobj-dev libpmempool-dev librbd-dev librdmacm-dev libsasl2-dev libsdl2-dev libsdl-image-gst \
libseccomp-dev libslirp-dev libsnappy-dev libspice-protocol-dev libspice-server-dev libssh-dev \
liburing-dev libusb-1.0-0-dev libusbredirhost-dev libusbredirparser-dev libvde-dev libvdeplug-dev \
libvdeslirp-dev libvte-2.91-dev libxen-dev libzstd-dev mesa-vulkan-drivers meson ninja-build \
pkg-config python3 python3-tomli python3-venv valgrind vulkan-validationlayers xfslibs-dev
RUN cd /tmp && \
git clone -b sdk-1.3.261.1 https://github.com/KhronosGroup/Vulkan-Headers.git && \
cd Vulkan-Headers && mkdir build && cd build && \
cmake .. -DCMAKE_INSTALL_PREFIX=/usr && make install && \
cd /tmp && \
git clone -b sdk-1.3.261.1 https://github.com/KhronosGroup/Vulkan-Loader.git && \
cd Vulkan-Loader && mkdir build && cd build && \
cmake .. -DCMAKE_INSTALL_PREFIX=/usr && make install && \
cd /tmp && \
git clone -b 1.1.0 --depth 1 https://gitlab.freedesktop.org/virgl/virglrenderer.git && \
cd virglrenderer && mkdir build && cd build && \
meson .. --prefix=/usr -Dvenus=true && \
ninja -j6 && ninja install
RUN cd /tmp && \
git clone --depth 1 -b v9.2.0 https://gitlab.com/qemu-project/qemu.git && \
cd qemu && mkdir build && cd build && \
../configure \
--prefix=/usr \
--target-list=x86_64-softmmu && \
ninja -j6 && \
ninja install && \
ninja clean
Saving this as Dockerfile, run following command to build docker image.
docker build -t qemu .
Please make sure that following output be seen
docker run -it --rm qemu-release qemu-system-x86_64 --version
QEMU emulator version 9.2.0 (v9.2.0)
Copyright (c) 2003-2024 Fabrice Bellard and the QEMU Project developers
Now, qemu-system-x86_64 with necessary libraries is successfully built as docker image. It means, the image tagged as qemu
contains /usr/bin/qemu-system-x86_64 and runtime libraries needed by qemu.
2. Linux Kernel
Venus depends on VirtIO-GPU shared memory feature on guest Linux Kernel. Linux kernel supported this feature from 5.16 upstream. Linux kernel has also many many compile time options, known as Kconfig or simply kernel configuration. Although Yocto Linux procedure will produce bzImage, it's more clear for us to build Kernel separately from YoctoLinux, because -kernel
option of qemu enable us to directly run the kernel as if kernel is just an certain kind of executable.
To build Linux kernel, docker container is also useful to setup prerequisite environment.
FROM ubuntu:24.04
# https://wiki.qemu.org/Hosts/Linux
RUN apt update && apt install -y git build-essential flex bison bc libssl-dev libelf-dev libncurses-dev
It can be done on Ubuntu PC without docker. For now I build it with docker build -t linux .
and run following steps.
docker run -it --rm -v $(pwd):$(pwd) -w $(pwd) linux /bin/bash
git clone --depth 1 -b v6.1.122 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1
cd linux-6.1
make O=build defconfig
./scripts/kconfig/merge_config.sh -O build arch/x86/configs/x86_64_defconfig ../virtual_device.cfg
make O=build bzImage -j $(nproc)
exit
As you see, first line will run docker container and commands until exit should run inside container. Here virtual_device.cfg is a fragment file which have following contents
cat virtual_device.cfg
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_PCI_LEGACY=y
CONFIG_VIRTIO_BLK=y
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_DRM_VIRTIO_GPU=y
Save it to $(pwd) directory before the above steps. You can add another Kconfig options to try qemu another feature. For this article I avoid going this another direction of trial. Finally you can find bzImage
, kernel file excutable by Qemu.
LD arch/x86/boot/compressed/vmlinux
ZOFFSET arch/x86/boot/zoffset.h
OBJCOPY arch/x86/boot/vmlinux.bin
AS arch/x86/boot/header.o
LD arch/x86/boot/setup.elf
OBJCOPY arch/x86/boot/setup.bin
BUILD arch/x86/boot/bzImage
Kernel: arch/x86/boot/bzImage is ready (#1)
make[1]: Leaving directory '/home/user/work/linux-release/build'
exit
ls linux-6.1/build/arch/x86/boot/bzImage
Final text should be like this. linux-6.1/build/arch/x86/boot/bzImage
can be seen from outside of docker environment. Pick it to your suitable location. If build tree is no longer needed, you can remove whole linux-6.1 directory by rm -rf
.
3. Yocto Linux rootfs
This step will be a little bit difficult and time consuming for some people. If you are not interested in customizing and engineering guest operating system, you can use my prebuilt rootfs to quickly try VirtIO-GPU Venus. In this case you can skip this step and move on to "Run Qemu & Try vkcube".
Official documentation of Yocto/bitbake is here. I delegate environment setup to this documentation for using bitbake command and concentrate on explaining customization point to enable VirtIO-GPU Venus from guest operating system. At first, please make sure you can build core-image-weston as below steps:
git clone git://git.yoctoproject.org/poky
cd poky
git checkout yocto-5.1.1
. ./oe-init-build-env build-styhead
bitbake core-image-weston
This will produce out-of-box rootfs at build-styhead/tmp/deploy/images/qemux86-64/core-image-weston-qemux86-64.rootfs.ext4. When using Yocto-5.1.1, Mesa 24.0.7 is used by default. The version 24.0.7 is recent enough to use -Dvulkan-drivers=virtio
from do_configure. However, this -Dvulkan-drivers=virtio
configuration is not put by default so that we need to add following bbappend files to mesa recipe.
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
VULKAN_DRIVERS = "virtio"
GALLIUMDRIVERS = "zink,virgl"
EXTRA_OEMESON += " \
-Dvulkan-layers=device-select \
"
FILES:mesa-vulkan-drivers += " \
/usr/lib/libVkLayer_MESA_device_select.so \
"
SRC_URI += " \
file://0001-venus-make-cross-device-optional.patch \
"
Note that, I added this commit to let vkCreateInstance successful on Qemu v9.2.0, ahead of Yocto mesa move on to more recent version of Mesa. Unless this fix, vkCreateInstance will fail due to missing VIRTGPU_PARAM_CROSS_DEVICE
. Only this fix is mandatory to use VirtIO-GPU Venus for Yocto-5.1.1. For this point, there is no vulkan application to call Vulkan API at all. "vkcube" can be added by
DEPENDS += "wayland wayland-native wayland-protocols"
EXTRA_OECMAKE = " \
-DBUILD_CUBE=ON \
-DCUBE_WSI_SELECTION=WAYLAND \
"
My prebuilt rootfs contains another modification which is not explained here.
Run Qemu & Try vkcube
Now you have all things to try VirtIO-GPU Venus on your laptop: qemu docker image, bzImage, core-image-weston-qemux86-64.ext4. Put it into your current directly and run following script:
#!/usr/bin/env bash
docker run -it --rm \
-w $(pwd) \
-v $(pwd):$(pwd) \
-v /run:/run \
-e XDG_RUNTIME_DIR=/run/user/1000 \
--privileged \
qemu \
qemu-system-x86_64 \
-m 4G -smp 4 --enable-kvm \
-kernel bzImage-release \
-append "console=ttyS0 root=/dev/vda nokaslr" \
-serial mon:stdio \
-display gtk,gl=on -vga none \
-device virtio-vga-gl,blob=on,hostmem=4G,venus=on \
-object memory-backend-memfd,id=mem1,size=4G \
-machine memory-backend=mem1 \
-drive file=core-image-weston-qemux86-64.rootfs.ext4,format=raw,if=virtio
Those who knows well about virtualization technologies may wonder why we need to doubly virtualize guest by docker + qemu, but it actually works. By using terms from computer science and virtualization technologies, Type2 + Type3 virtualization can co-exist. Note that, KVM sometimes regardeed as Type-1, but here I don't deep dive into this direction. Now, you can see the console like
Poky (Yocto Project Reference Distro) 5.1.1 qemux86-64 ttyS0
qemux86-64 login:
Just enter "root" here. Run vkcube by
root@qemux86-64:~# export XDG_RUNTIME_DIR=/run/user/1000/
root@qemux86-64:~# export WAYLAND_DISPLAY=wayland-1
root@qemux86-64:~# export VK_DRIVER_FILES=/usr/share/vulkan/icd.d/virtio_icd.x86_64.json
root@qemux86-64:~#
root@qemux86-64:~# vkcube
Selected GPU 0: Virtio-GPU Venus (Intel(R) HD Graphics 520 (SKL GT2)), type: IntegratedGpu
Success!!
Benckmark result
There are two well-known GPU benckmarks: glmark2, vkmark. I added these two from Yocto recipe. I omit whole procedure to do it, but again my prebuilt rootfs contains both these two benchmarks. Still you can do the same with me quickly.
vkmark
- Ubuntu
- VirtIO-GPU Venus
- VirtIO-GPU Venus (offscreen)
Result (Ubuntu)
=======================================================
vkmark 2017.08
=======================================================
Vendor ID: 0x8086
Device ID: 0x1916
Device Name: Intel(R) HD Graphics 520 (SKL GT2)
Driver Version: 100663305
Device UUID: 50ffa5a61895bba5200df0064824bd39
=======================================================
[vertex] device-local=true: FPS: 3968 FrameTime: 0.252 ms
[vertex] device-local=false: FPS: 4062 FrameTime: 0.246 ms
[texture] anisotropy=0: FPS: 3767 FrameTime: 0.265 ms
[texture] anisotropy=16: FPS: 3770 FrameTime: 0.265 ms
[shading] shading=gouraud: FPS: 3190 FrameTime: 0.313 ms
[shading] shading=blinn-phong-inf: FPS: 3239 FrameTime: 0.309 ms
[shading] shading=phong: FPS: 3365 FrameTime: 0.297 ms
[shading] shading=cel: FPS: 3319 FrameTime: 0.301 ms
[effect2d] kernel=edge: FPS: 3381 FrameTime: 0.296 ms
[effect2d] kernel=blur: FPS: 1273 FrameTime: 0.786 ms
[desktop] <default>: FPS: 876 FrameTime: 1.142 ms
[cube] <default>: FPS: 5195 FrameTime: 0.192 ms
[clear] <default>: FPS: 4682 FrameTime: 0.214 ms
=======================================================
vkmark Score: 3391
=======================================================
This is expected as highest result without any GPU virtualization. For this picture, I used -display gtk,gl=on,full-screen=on
to see guest screen as full-screen mode. Gtk+3 display default size was too small to see the content of vkmark.
Result (VirtIO-GPU Venus)
root@qemux86-64:~# vkmark
=======================================================
vkmark 2017.08
=======================================================
Vendor ID: 0x8086
Device ID: 0x1916
Device Name: Virtio-GPU Venus (Intel(R) HD Graphics 520 (SKL GT2))
Driver Version: 100663303
Device UUID: b07efb5ab969942c4d4245e8c29beaf1
=======================================================
[vertex] device-local=true: FPS: 747 FrameTime: 1.339 ms
[vertex] device-local=false: FPS: 737 FrameTime: 1.357 ms
[texture] anisotropy=0: FPS: 710 FrameTime: 1.408 ms
[texture] anisotropy=16: FPS: 707 FrameTime: 1.414 ms
[shading] shading=gouraud: FPS: 674 FrameTime: 1.484 ms
[shading] shading=blinn-phong-inf: FPS: 684 FrameTime: 1.462 ms
[shading] shading=phong: FPS: 692 FrameTime: 1.445 ms
[shading] shading=cel: FPS: 695 FrameTime: 1.439 ms
[effect2d] kernel=edge: FPS: 870 FrameTime: 1.149 ms
[effect2d] kernel=blur: FPS: 708 FrameTime: 1.412 ms
[desktop] <default>: FPS: 486 FrameTime: 2.058 ms
[cube] <default>: FPS: 758 FrameTime: 1.319 ms
[clear] <default>: FPS: 800 FrameTime: 1.250 ms
=======================================================
vkmark Score: 712
=======================================================
This is VirtIO-GPU Venus solution performance, compared to native GPU.
Result (VirtIO-GPU Venus (offscreen))
root@qemux86-64:~# vkmark
=======================================================
vkmark 2017.08
=======================================================
Vendor ID: 0x8086
Device ID: 0x1916
Device Name: Virtio-GPU Venus (Intel(R) HD Graphics 520 (SKL GT2))
Driver Version: 100663303
Device UUID: b07efb5ab969942c4d4245e8c29beaf1
=======================================================
[vertex] device-local=true: FPS: 1521 FrameTime: 0.657 ms
[vertex] device-local=false: FPS: 1536 FrameTime: 0.651 ms
[texture] anisotropy=0: FPS: 1344 FrameTime: 0.744 ms
[texture] anisotropy=16: FPS: 1341 FrameTime: 0.746 ms
[shading] shading=gouraud: FPS: 1336 FrameTime: 0.749 ms
[shading] shading=blinn-phong-inf: FPS: 1331 FrameTime: 0.751 ms
[shading] shading=phong: FPS: 1382 FrameTime: 0.724 ms
[shading] shading=cel: FPS: 1403 FrameTime: 0.713 ms
[effect2d] kernel=edge: FPS: 1863 FrameTime: 0.537 ms
[effect2d] kernel=blur: FPS: 1499 FrameTime: 0.667 ms
[desktop] <default>: FPS: 818 FrameTime: 1.222 ms
[cube] <default>: FPS: 1675 FrameTime: 0.597 ms
[clear] <default>: FPS: 1885 FrameTime: 0.531 ms
=======================================================
vkmark Score: 1456
=======================================================
Final result require some explanation about off-screen. After 300 seconds from booting qemu, weston, the gray desktop, goes into inactive mode and don't output any screen content at all. This corresponds to sleep mode of usual laptop."Display output is not active" is drawn by Qemu and this indicates that guest virtual machine doesn't put any output. Due to some reason, vkmark hit higher score on this inactive status.
Summary is here.
scene | Ubuntu | VirtIO-GPU Venus (offscreen) |
VirtIO-GPU Venus (onscreen) |
---|---|---|---|
vertex device-local=true | 3968 | 1521 | 747 |
vertex device-local=false | 4062 | 1536 | 737 |
texture anisotropy=0 | 3767 | 1344 | 710 |
texture anisotropy=16 | 3770 | 1341 | 707 |
shading shading=gouraud | 3190 | 1336 | 674 |
shading shading=blinn-phong-inf | 3239 | 1331 | 684 |
shading shading=phong | 3365 | 1382 | 692 |
shading shading=cel | 3319 | 1403 | 695 |
effect2d kernel=edge | 3381 | 1863 | 870 |
effect2d kernel=blur | 1273 | 1499 | 708 |
desktop default | 876 | 818 | 486 |
cube default | 5195 | 1675 | 758 |
clear default | 4682 | 1885 | 800 |
vkmark score | 3391 | 1456 | 712 |
Off-screen result is not affected by Window System Integration, which depends on Qemu implementation arround Gtk+, and in this case guest system also has windowing system: weston. Precisely speaking, drawing contents by GPU and display its output into physical display relay on different mechanism. By using virtio-vga-gl
(compared to virtio-gpu-gl
), latter part also relay on VirtIO-GPU scan-out feature. While GPU performance only determined by first part (means drawing content by GPU), off-screen result represents potential performance upper bounds of Virtio-GPU Venus solution.
glmark2: Zink vs VirGL
Zink is also relatively new solution to convert OpenGL commands into VirtIO-GPU Venus. By using Zink, OpenGL commands will become Vulkan commands on Host side via VirtIO-GPU Venus transport. We've already done the preparation to use zink for any OpenGL application. Remember that mesa configure contains -Dgallium-drivers=zink,virgl
. This was preparation. To use zink for glmark2, run
MESA_LOADER_DRIVER_OVERRIDE=zink glmark2-es2-wayland
is enough. export MESA_LOADER_DRIVER_OVERRIDE=zink
will set zink by default.
- Ubuntu
- VirGL offscreen
- Zink offscreen
Ubuntu
user@user:~$ glmark2-es2-wayland
=======================================================
glmark2 2023.01
=======================================================
OpenGL Information
GL_VENDOR: Intel
GL_RENDERER: Mesa Intel(R) HD Graphics 520 (SKL GT2)
GL_VERSION: OpenGL ES 3.2 Mesa 24.0.9-0ubuntu0.3
Surface Config: buf=32 r=8 g=8 b=8 a=8 depth=24 stencil=0 samples=0
Surface Size: 800x600 windowed
=======================================================
[build] use-vbo=false: FPS: 2006 FrameTime: 0.499 ms
[build] use-vbo=true: FPS: 4201 FrameTime: 0.238 ms
[texture] texture-filter=nearest: FPS: 3674 FrameTime: 0.272 ms
[texture] texture-filter=linear: FPS: 3568 FrameTime: 0.280 ms
[texture] texture-filter=mipmap: FPS: 3530 FrameTime: 0.283 ms
[shading] shading=gouraud: FPS: 2999 FrameTime: 0.333 ms
[shading] shading=blinn-phong-inf: FPS: 2528 FrameTime: 0.396 ms
[shading] shading=phong: FPS: 2934 FrameTime: 0.341 ms
[shading] shading=cel: FPS: 2802 FrameTime: 0.357 ms
[bump] bump-render=high-poly: FPS: 1158 FrameTime: 0.864 ms
[bump] bump-render=normals: FPS: 4161 FrameTime: 0.240 ms
[bump] bump-render=height: FPS: 3880 FrameTime: 0.258 ms
[effect2d] kernel=0,1,0;1,-4,1;0,1,0;: FPS: 3533 FrameTime: 0.283 ms
[effect2d] kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: FPS: 1245 FrameTime: 0.804 ms
[pulsar] light=false:quads=5:texture=false: FPS: 4180 FrameTime: 0.239 ms
[desktop] blur-radius=5:effect=blur:passes=1:separable=true:windows=4: FPS: 1141 FrameTime: 0.876 ms
[desktop] effect=shadow:windows=4: FPS: 1853 FrameTime: 0.540 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 467 FrameTime: 2.144 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: FPS: 539 FrameTime: 1.856 ms
[buffer] columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 492 FrameTime: 2.036 ms
[ideas] speed=duration: FPS: 2174 FrameTime: 0.460 ms
[jellyfish] <default>: FPS: 2946 FrameTime: 0.340 ms
[terrain] <default>: FPS: 175 FrameTime: 5.741 ms
[shadow] <default>: FPS: 1132 FrameTime: 0.884 ms
[refract] <default>: FPS: 282 FrameTime: 3.549 ms
[conditionals] fragment-steps=0:vertex-steps=0: FPS: 2445 FrameTime: 0.409 ms
[conditionals] fragment-steps=5:vertex-steps=0: FPS: 2722 FrameTime: 0.367 ms
[conditionals] fragment-steps=0:vertex-steps=5: FPS: 2440 FrameTime: 0.410 ms
[function] fragment-complexity=low:fragment-steps=5: FPS: 2544 FrameTime: 0.393 ms
[function] fragment-complexity=medium:fragment-steps=5: FPS: 3001 FrameTime: 0.333 ms
[loop] fragment-loop=false:fragment-steps=5:vertex-steps=5: FPS: 2598 FrameTime: 0.385 ms
[loop] fragment-steps=5:fragment-uniform=false:vertex-steps=5: FPS: 2615 FrameTime: 0.383 ms
[loop] fragment-steps=5:fragment-uniform=true:vertex-steps=5: FPS: 2827 FrameTime: 0.354 ms
=======================================================
glmark2 Score: 2386
=======================================================
Result (VirGL offscreen)
root@qemux86-64:~# glmark2-es2-wayland
=======================================================
glmark2 2023.01
=======================================================
OpenGL Information
GL_VENDOR: Mesa
GL_RENDERER: virgl (Mesa Intel(R) HD Graphics 520 (SKL GT2))
GL_VERSION: OpenGL ES 3.2 Mesa 24.0.7
Surface Config: buf=32 r=8 g=8 b=8 a=8 depth=32 stencil=0 samples=0
Surface Size: 800x600 windowed
=======================================================
[build] use-vbo=false: FPS: 1193 FrameTime: 0.838 ms
[build] use-vbo=true: FPS: 1637 FrameTime: 0.611 ms
[texture] texture-filter=nearest: FPS: 1276 FrameTime: 0.784 ms
[texture] texture-filter=linear: FPS: 782 FrameTime: 1.279 ms
[texture] texture-filter=mipmap: FPS: 1216 FrameTime: 0.823 ms
[shading] shading=gouraud: FPS: 786 FrameTime: 1.273 ms
[shading] shading=blinn-phong-inf: FPS: 1311 FrameTime: 0.763 ms
[shading] shading=phong: FPS: 791 FrameTime: 1.265 ms
[shading] shading=cel: FPS: 532 FrameTime: 1.881 ms
[bump] bump-render=high-poly: FPS: 182 FrameTime: 5.507 ms
[bump] bump-render=normals: FPS: 1624 FrameTime: 0.616 ms
[bump] bump-render=height: FPS: 1353 FrameTime: 0.739 ms
[effect2d] kernel=0,1,0;1,-4,1;0,1,0;: FPS: 182 FrameTime: 5.511 ms
[effect2d] kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: FPS: 182 FrameTime: 5.517 ms
[pulsar] light=false:quads=5:texture=false: FPS: 1030 FrameTime: 0.971 ms
[desktop] blur-radius=5:effect=blur:passes=1:separable=true:windows=4: FPS: 180 FrameTime: 5.564 ms
[desktop] effect=shadow:windows=4: FPS: 181 FrameTime: 5.538 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 83 FrameTime: 12.126 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: FPS: 404 FrameTime: 2.479 ms
[buffer] columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 84 FrameTime: 11.985 ms
[ideas] speed=duration: FPS: 787 FrameTime: 1.271 ms
[jellyfish] <default>: FPS: 181 FrameTime: 5.528 ms
[terrain] <default>: FPS: 141 FrameTime: 7.126 ms
[shadow] <default>: FPS: 799 FrameTime: 1.252 ms
[refract] <default>: FPS: 166 FrameTime: 6.037 ms
[conditionals] fragment-steps=0:vertex-steps=0: FPS: 338 FrameTime: 2.964 ms
[conditionals] fragment-steps=5:vertex-steps=0: FPS: 1054 FrameTime: 0.949 ms
[conditionals] fragment-steps=0:vertex-steps=5: FPS: 999 FrameTime: 1.001 ms
[function] fragment-complexity=low:fragment-steps=5: FPS: 911 FrameTime: 1.098 ms
[function] fragment-complexity=medium:fragment-steps=5: FPS: 182 FrameTime: 5.503 ms
[loop] fragment-loop=false:fragment-steps=5:vertex-steps=5: FPS: 394 FrameTime: 2.544 ms
[loop] fragment-steps=5:fragment-uniform=false:vertex-steps=5: FPS: 686 FrameTime: 1.459 ms
[loop] fragment-steps=5:fragment-uniform=true:vertex-steps=5: FPS: 732 FrameTime: 1.367 ms
=======================================================
glmark2 Score: 677
=======================================================
root@qemux86-64:~#
Result (Zink offscreen)
root@qemux86-64:~# MESA_LOADER_DRIVER_OVERRIDE=zink glmark2-es2-wayland
=======================================================
glmark2 2023.01
=======================================================
OpenGL Information
GL_VENDOR: Mesa
GL_RENDERER: zink Vulkan 1.3(Virtio-GPU Venus (Intel(R) HD Graphics 520 (SKL GT2)) (MESA_VENUS))
GL_VERSION: OpenGL ES 3.2 Mesa 24.0.7
Surface Config: buf=32 r=8 g=8 b=8 a=8 depth=24 stencil=0 samples=0
Surface Size: 800x600 windowed
=======================================================
[build] use-vbo=false: FPS: 97 FrameTime: 10.417 ms
[build] use-vbo=true: FPS: 1430 FrameTime: 0.699 ms
[texture] texture-filter=nearest: FPS: 1342 FrameTime: 0.745 ms
[texture] texture-filter=linear: FPS: 1330 FrameTime: 0.752 ms
[texture] texture-filter=mipmap: FPS: 1317 FrameTime: 0.760 ms
[shading] shading=gouraud: FPS: 1264 FrameTime: 0.792 ms
[shading] shading=blinn-phong-inf: FPS: 1262 FrameTime: 0.793 ms
[shading] shading=phong: FPS: 1252 FrameTime: 0.799 ms
[shading] shading=cel: FPS: 1251 FrameTime: 0.799 ms
[bump] bump-render=high-poly: FPS: 1029 FrameTime: 0.972 ms
[bump] bump-render=normals: FPS: 1371 FrameTime: 0.730 ms
[bump] bump-render=height: FPS: 1353 FrameTime: 0.740 ms
[effect2d] kernel=0,1,0;1,-4,1;0,1,0;: FPS: 934 FrameTime: 1.072 ms
[effect2d] kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: FPS: 819 FrameTime: 1.222 ms
[pulsar] light=false:quads=5:texture=false: FPS: 1016 FrameTime: 0.985 ms
[desktop] blur-radius=5:effect=blur:passes=1:separable=true:windows=4: FPS: 529 FrameTime: 1.891 ms
[desktop] effect=shadow:windows=4: FPS: 673 FrameTime: 1.487 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 183 FrameTime: 5.472 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: FPS: 99 FrameTime: 10.160 ms
[buffer] columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 182 FrameTime: 5.517 ms
[ideas] speed=duration: FPS: 846 FrameTime: 1.182 ms
[jellyfish] <default>: FPS: 572 FrameTime: 1.750 ms
[terrain] <default>: FPS: 142 FrameTime: 7.044 ms
[shadow] <default>: FPS: 766 FrameTime: 1.305 ms
[refract] <default>: FPS: 176 FrameTime: 5.683 ms
[conditionals] fragment-steps=0:vertex-steps=0: FPS: 1066 FrameTime: 0.938 ms
[conditionals] fragment-steps=5:vertex-steps=0: FPS: 1062 FrameTime: 0.942 ms
[conditionals] fragment-steps=0:vertex-steps=5: FPS: 1058 FrameTime: 0.946 ms
[function] fragment-complexity=low:fragment-steps=5: FPS: 1055 FrameTime: 0.949 ms
[function] fragment-complexity=medium:fragment-steps=5: FPS: 1058 FrameTime: 0.946 ms
[loop] fragment-loop=false:fragment-steps=5:vertex-steps=5: FPS: 1052 FrameTime: 0.951 ms
[loop] fragment-steps=5:fragment-uniform=false:vertex-steps=5: FPS: 1058 FrameTime: 0.946 ms
[loop] fragment-steps=5:fragment-uniform=true:vertex-steps=5: FPS: 1048 FrameTime: 0.955 ms
=======================================================
glmark2 Score: 898
=======================================================
root@qemux86-64:~#
Summary is here.
scene | Ubuntu | VirGL | Zink |
---|---|---|---|
build use-vbo=false | 2006 | 1193 | 97 |
build use-vbo=true | 4201 | 1637 | 1430 |
texture texture-filter=nearest: | 3674 | 1276 | 1342 |
texture texture-filter=linear: | 3568 | 782 | 1330 |
texture texture-filter=mipmap: | 3530 | 1216 | 1317 |
shading shading=gouraud: | 2999 | 786 | 1264 |
shading shading=blinn-phong-inf: | 2528 | 1311 | 1262 |
shading shading=phong: | 2934 | 791 | 1252 |
shading shading=cel: | 2802 | 532 | 1251 |
bump bump-render=high-poly: | 1158 | 182 | 1029 |
bump bump-render=normals: | 4161 | 1624 | 1371 |
bump bump-render=height: | 3880 | 1353 | 1353 |
effect2d kernel=0,1,0;1,-4,1;0,1,0;: | 3533 | 182 | 934 |
effect2d kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: | 1245 | 182 | 819 |
pulsar light=false:quads=5:texture=false: | 4180 | 1030 | 1016 |
desktop blur-radius=5:effect=blur:passes=1:separable=true:windows=4: | 1141 | 180 | 529 |
desktop effect=shadow:windows=4: | 1853 | 181 | 673 |
buffer columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: |
467 | 83 | 183 |
buffer columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: |
539 | 404 | 99 |
buffer columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: |
492 | 84 | 182 |
ideas speed=duration: | 2174 | 787 | 846 |
jellyfish default: | 2946 | 181 | 572 |
terrain default: | 175 | 141 | 142 |
shadow default: | 1132 | 799 | 766 |
refract default: | 282 | 166 | 176 |
conditionals fragment-steps=0:vertex-steps=0: | 2445 | 338 | 1066 |
conditionals fragment-steps=5:vertex-steps=0: | 2722 | 1054 | 1062 |
conditionals fragment-steps=0:vertex-steps=5: | 2440 | 999 | 1058 |
function fragment-complexity=low:fragment-steps=5: | 2544 | 911 | 1055 |
function fragment-complexity=medium:fragment-steps=5: | 3001 | 182 | 1058 |
loop fragment-loop=false:fragment-steps=5:vertex-steps=5: | 2598 | 394 | 1052 |
loop fragment-steps=5:fragment-uniform=false:vertex-steps=5: | 2615 | 686 | 1058 |
loop fragment-steps=5:fragment-uniform=true:vertex-steps=5: | 2827 | 732 | 1048 |
glmark2 Score | 2386 | 677 | 898 |
Zink is superior to classic VirGL, based on this result. Expert can analyze this result further by considering characteristics of each scene. I will omit this in this article, though there are many interesting point even from my view.
Troubleshoot
Starting from VN_DEBUG
environment variable is the best way.
VN_DEBUG=all vkcube
90% of VirtIO-GPU Venus trouble will be handled by this debugging feature. For example, if I missed venus=on
toggle from -device virtio-vga-gl,blob=on,hostmem=4G,venus=on
, VN_DEBUG will show
root@qemux86-64:~# VN_DEBUG=all vkcube
MESA-VIRTIO: debug: vn_env is as below:
debug = 0x1ff
perf = 0x0
draw_cmd_batch_limit = 4294967295
relax_base_sleep_us = 160
MESA-VIRTIO: debug: failed to connect to /tmp/.virgl_test: No such file or directory
MESA-VIRTIO: debug: using DRM device /dev/dri/renderD128
MESA-VIRTIO: debug: failed to get venus v0 capset: Invalid argument
MESA-[ 13.593327] audit: type=1701 audit(1735660479.644:5): auid=4294967295 uid=0 gid=0 ses=4294967295 subj=kernel pid=285 comm="vkcube" exe="/usr/bin/vkcube" sig=6 res=1
VIRTIO: debug: vn_CreateInstance: VK_ERROR_INITIALIZATION_FAILED
vkcube: /usr/src/debug/vulkan-tools/1.3.290.0/cube/cube.c:3622: demo_init_vk: Assertion `!err' failed.
Aborted (core dumped)
root@qemux86-64:~#
Then I could realize that venus capset (capability set) is not notified from Qemu.
Conclusion & Remarks
This article explains how to enable VirtIO-GPU Venus on your Qemu machine. Remark is that, while I am trying venus, there are some hang, crashing guest machine. This solution seems to have some points to be improved. The mesa "24.0.7" which is used for this article is in real not the latest version, so that some of them will be fixed on up-to-date version of Mesa.
About benchmarking, I didn't fully expose precondition and provide just one trial result. It also contains intentional sample drop when I encounter some crash, hangs on VirtIO-GPU Venus side experiment. This is also important to notice. For this moment, Venus is not simply super solution compared to VirGL. VirGL is stable enough while Venus not. I believe just doing it on your laptop may answer every unknown point. Please see the real.