文章目录

  • 概述
  • 基本环境搭建
  • 组件编译
  • mesa
  • libvirt
  • qemu-kvm
  • virglrenderer
  • 应用


概述

  • virtio-gpu是GPU分时复用方案,相对于透传方案,virito-gpu的优点时可以模拟更多的gpu,缺点是因为GPU需要处理更多的请求,相比透传方案,调度的损耗多,牺牲了GPU部分性能。
  • 本文的实践主要基于virtio-gpu官方博客的搭建指导。

基本环境搭建

  • 选择centos 8图形界面,CentOS Linux release 8.1.1911
  • 安装OS之后,如果不被墙,可以使用默认的yum源,如果没有yum源配置,安装centos-repos-8.1-1.1911.0.8.el8.x86_64.rpm
  • yum高级工具yumdownloader安装yum -y install yum-utils.noarch
  • 基本编译开发套件安装yum -y groupinstall Development

组件编译

mesa

git clone https://github.com/mesa3d/mesa.git
yum-builddep mesa
yum install -y meson
mkdir build; cd build;
meson ..
cd .. ; meson reconfigure --prefix=/usr -Dgallium-drivers=virgl
cd build
ninja
ninja install

libvirt

  • wget http://vault.centos.org/8.0.1905/virt/Source/advanced-virtualization/libvirt-5.6.0-10.el8.src.rpm
  • 安装libvirt源码包rpm -ivh libvirt-5.6.0-10.el8.src.rpm
  • 安装libvirt编译环境依赖包yum-builddep libvirt
  • 编译libvirt源码包cd $HOME/rpmbuild && rpmbuild -bb SPECS/libvirt.spec --define "_topdir $(pwd)"
  • 进入RPMS目录安装rpm包

qemu-kvm

  • wget http://vault.centos.org/8.0.1905/virt/Source/advanced-virtualization/qemu-kvm-4.1.0-23.el8.1.src.rpm
  • 安装qemu-kvm源码包rpm -ivh qemu-kvm-4.1.0-23.el8.1.src.rpm
  • 安装qemu-kvm编译环境依赖包yum-builddep qemu-kvm
  • 高版本qemu直接rpmbuild编译会报缺少virglrenderer-devel,这个依赖在centos上没有找到,直接下载源码编译解决这个依赖问题,步骤在下一节介绍,假设现在qemu编译依赖已经解决
  • 取出qemu-kvm源码包cd $HOME/rpmbuild/SOURCES && tar -xf qemu-4.1.0.tar.xz"
  • 进入源码目录配置./configure --target-list=x86_64-softmmu --prefix=/usr --enable-kvm --enable-virglrenderer
  • 编译并安装make -j$(nproc --ignore=1) && make install

virglrenderer

  • virglrenderer是一个开源项目virgil3d提供的开源库,它的主要功能是针对虚拟化场景,为QEMU提供一个具有3D图形处理的显卡,其使用方式就是为QEMU提供一组3D图形处理的接口。QEMU通过调用virglrenderer的库接口实现主机侧的3D图形加速处理。
  • virglrenderer编译依赖两个工具分别是cmak和ninja,分别安装yum install -y cmake ninja-build
  • virglrenderer还依赖一个libepoxy库,分别下载这两个组件的源码
  • 下载libepoxy git clone https://github.com/anholt/libepoxy.git
  • 下载virglrenderer git clone git://anongit.freedesktop.org/virglrenderer
  • 编译libexpoxy依赖glesv2,安装yum install mesa-libGLES-devel
  • 编译libexpoxy,只能用ninja方式编译:
mkdir _build && cd _build
meson --prefix=/usr
ninja
sudo ninja install
  • 编译virglrender,可以用ninja方式编译,也可以用make编译,步骤如下:
./configure --enable-autotools --enable-debug --prefix=/usr
make -j$(nproc --ignore=1)
make install
  • 在上述所有组件编译安装完成后,运行virsh version查看虚拟化组件版本,成功的输出应该是这样:

kvm virtio kvm VirtIO-GPU_git

应用

  • 准备磁盘文件qemu-img create -f qcow2 /home/test_vm.qcow2 80G
  • 创建测试虚机的xml文件test_vm.xml如下:
<domain type='kvm' id='2'>
  <name>test_vm</name>
  <uuid>720a0f9f-2893-4712-87e4-b7a61454dd7a</uuid>
  <maxMemory slots='16' unit='KiB'>16777216</maxMemory>
  <memory unit='KiB'>4194304</memory>
  <currentMemory unit='KiB'>4194304</currentMemory>
  <vcpu placement='static'>4</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch='x86_64' machine='pc-i440fx-4.1'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <cpu>
    <numa>
      <cell id='0' cpus='0-1' memory='2097152' unit='KiB'/>
      <cell id='1' cpus='2-3' memory='2097152' unit='KiB'/>
    </numa>
  </cpu>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/home/test_vm.qcow2'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </disk>
    <controller type='usb' index='0' model='piix3-uhci'>
      <alias name='usb'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'>
      <alias name='pci.0'/>
    </controller>
    <input type='mouse' bus='ps2'>
      <alias name='input0'/>
    </input>
    <input type='keyboard' bus='ps2'>
      <alias name='input1'/>
    </input>
    <graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1' keymap='en-us'>
      <listen type='address' address='127.0.0.1'/>
    </graphics>
    <video>
      <model type='cirrus' vram='16384' heads='1' primary='yes'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </memballoon>
  </devices>
  <seclabel type='dynamic' model='selinux' relabel='yes'>
    <label>system_u:system_r:svirt_t:s0:c799,c857</label>
    <imagelabel>system_u:object_r:svirt_image_t:s0:c799,c857</imagelabel>
  </seclabel>
  <seclabel type='dynamic' model='dac' relabel='yes'>
    <label>+0:+0</label>
    <imagelabel>+0:+0</imagelabel>
  </seclabel>
</domain>
  • 定义虚拟机virsh define test_vm.xml
  • 关闭防火墙,设置qemu访问权限:
cat /etc/sysconfig/selinux
SELINUX=disabled
cat /etc/libvirt/qemu.conf 
user = "root"
group = "root"
  • 启动虚机virsh start test_vm,这时启动的虚机还没有配置virtio-gpu
  • libvirt默认将第一个显卡配置成vga模式保持兼容性,同时如果显卡设置成virtio,默认使用virtio-gpu-pci设备,因此修改libvirt,让其默认使用virtio-gpu,重新编译libvirt。
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index a5958c3..0e1a5cf 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4660,9 +4660,11 @@ qemuBuildDeviceVideoStr(const virDomainDef *def,
      * model with VGA compatibility mode.  For some video devices on some
      * architectures there might not be such model so fallback to one
      * without VGA compatibility mode. */
+#if 0
     if (video->primary && qemuDomainSupportsVideoVga(video, qemuCaps))
         model = qemuDeviceVideoTypeToString(video->type);
     else
+#endif
         model = qemuDeviceVideoSecondaryTypeToString(video->type);
 
     if (!model || STREQ(model, "")) {
@@ -4673,11 +4675,13 @@ qemuBuildDeviceVideoStr(const virDomainDef *def,
     }
 
     if (STREQ(model, "virtio-gpu")) {
+#if 0
         if (qemuBuildVirtioDevStr(&buf, "virtio-gpu", qemuCaps,
                                   VIR_DOMAIN_DEVICE_VIDEO, video) < 0) {
             goto error;
         }
     } else {
+#endif
         virBufferAsprintf(&buf, "%s", model);
     }
  • 启动虚机时在libvirt xml中添加如下内容:
<graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>					/* 1 */
<graphics type='egl-headless'>														/* 2 */
  <gl rendernode='/dev/dri/renderD128'/>
</graphics>
<video>																				/* 3 */
  <model type='virtio' vram='16384' heads='1' primary='yes'/>
</video>
<video>																				/* 4 */
  <model type='virtio' vram='16384' heads='1'/>
</video>
1. 启动qemu vnc server,客户端使用vnc client远程连接虚机
2. 添加一个显示器设备,设备类型为egl-headless,与vnc/spic/sdl显示设备不同,egl-headless没有提供显示窗口或者终端,它只是用来指示qemu在执行图形处理时使用OpenGL加速。rendernode指示qemu在处理图形时使用host上的那个DRI设备加速,通常情况下不需要设置,qemu默认使用第一个显卡对应的DRI设备,只有在有多个显卡时才有用。
3. 添加一张virtio-vga的显卡作为主显卡,virtio-vga显示是virtio-gpu加上stdvga的结合。它兼容vga模式。
4. 添加一张virtio-gpu的显卡
  • 最后启动虚机,qemu命令行如下:
-vnc 0.0.0.0:0 															/* 5 */
-display egl-headless,rendernode=/dev/dri/renderD128					/* 6 */ 
-device virtio-vga,id=video0,max_outputs=1,bus=pci.0,addr=0xb 			/* 7 */ 
-device virtio-gpu-pci,id=video1,max_outputs=1,bus=pci.0,addr=0x2		/* 8 */
5. vnc server,端口5900
6. 设置qemu处理GL操作时使用host上的DRI设备
7. 增加virtio-gpu兼容vga模式的显卡
8. 增加virtio-gpu显卡