本文将首先介绍 Virgl 的基本概念和架构,主要从全局的角度分析虚拟机请求到物理机上的处理流程。
1. Virgl图形软件栈
如图所示,详细地展示了virgl技术图形软件栈。从整体来看可以分为两个层次:Guest端和Host端,接下来将分别介绍每一层涉及的概念。
2. Guest端
2.1 Mesa驱动
-
在本文中,我们讨论的“Guest”端,指的是基于 QEMU 启动的 Linux 虚拟机。在这个虚拟机环境中,应用程序在执行过程中会调用相应的用户层驱动。例如,
OpenGL
应用会利用Virgl
驱动,Vulkan
应用则会调用Venus
驱动,而OpenCL
应用会依赖VCL
驱动。这些驱动都是在 Mesa 中专门为支持 Virgl 技术而开发的开源用户态驱动。 -
这些用户态驱动的核心功能是将虚拟机中的应用程序对硬件的请求 API 进行指令翻译。以 Virgl 驱动为例,它将 OpenGL 指令转换为对应的 Virgl 指令,从而实现高效的图形渲染和处理。这种翻译机制不仅优化了虚拟化环境中的性能,还确保了应用程序能够充分利用底层硬件的能力。
2.2 Virtio-gpu kernel driver
- 在 Linux 系统内核中,包含了一个 virtio-gpu 驱动,该驱动承担着双重职责:一方面,它负责接收来自上层用户态驱动的请求;另一方面,它与运行在 Host 端的 QEMU virtio-gpu 设备进行交互。在这一层,驱动会对上层发送的 Virgl 指令进行进一步的封装,以便将其传递给 virtio-gpu 设备。virtio-gpu 设备可以根据封装头中的指令类型,对请求进行相应的处理。
2.3 Guest GL 调用栈
总的来看Guest内部的GL应用的请求流程如下图所示。
3. Host端
3.1 QEMU Virtio-gpu device
- 在主机端,有一个基于 QEMU 中 virtio 规范实现的 virtio-gpu 设备,负责模拟 GPU 硬件并响应 Guest 中的 GPU 指令请求。
- 实际上,不仅是 GPU 设备,QEMU 中还包含许多其他 virtio 设备,例如
virtio-net
设备、virtio-blk
设备和virtio-serial
设备等。每个设备(作为后端)都对应于 Guest 中的一个 virtio 设备驱动(作为前端),二者通过 virtqueue 实现了一套统一的 virtio 通信机制。上层的 virtio 设备内核驱动通过这一通信机制将数据请求传递给相应的 virtio 设备。
- 此外,virtio-gpu 设备还定义了一套 VIRTIO_GPU 支持的命令列表,以便后续指令的分发和处理。
3.2 Virglrenderer
- Virglrenderer可以理解为一个动态库,Virtio-gpu device在完成对上层请求数据的读取后,会根据转发数据头中的CMD类型,调用对应的virglrenderer库中的函数,并将virgl指令数据地址交付给virglrenderer。
- Virglrenderer库核心任务:对virgl指令进行解码(decode)操作,转化为宿主机可识别OpenGL调用。
- 当然如果虚拟机中的请求为vulkan请求,那么就不是专户阿伟OpenGL调用了,而是对应的vulkan调用。
4. Host端——用户态驱动和内核态驱动
- Virglrenderer中通过将virgl指令翻译成OpenGL调用,这些调用将请求交付给主机上对应的OpenGL用户态实现,以及内核态GPU驱动,从而最终操控硬件完成请求的响应。
后续待补充系列文章:
- 如何在 QEMU 中配置和使用 Virgl,包括所需的依赖项、启动参数及调试技巧。
- 虚拟机如何通过 VirtIO 协议与 QEMU 进行通信,确保虚拟机与物理 GPU 之间的高效数据传输。
- Virglrenderer 的角色,以及它如何在用户空间处理 OpenGL API 调用,提供无缝的图形加速体验。
- 分析 Virgl 在不同虚拟化场景下的性能表现,比较其与传统软件渲染的优势与不足。