1. 概述
本文档详细介绍 QEMU 中 VirtIO GPU 设备的架构设计,特别是 Virgl 3D 渲染加速的实现机制。VirtIO GPU 是一个半虚拟化的图形设备,它允许虚拟机利用宿主机的 GPU 资源进行 2D 和 3D 图形渲染。
2. 目录结构与文件关系
2.1 核心目录
qemu/
├── hw/
│ ├── virtio/ # VirtIO 框架层(通用基础设施)
│ │ ├── virtio.c # VirtIO 核心实现
│ │ ├── virtio-bus.c # VirtIO 总线抽象
│ │ ├── virtio-pci.c # PCI 传输层
│ │ └── virtio-mmio.c # MMIO 传输层
│ │
│ └── display/ # 显示设备层(GPU 功能实现)
│ ├── virtio-gpu-base.c # GPU 基础功能
│ ├── virtio-gpu.c # GPU 2D 功能
│ ├── virtio-gpu-virgl.c # GPU 3D/Virgl 加速
│ ├── virtio-gpu-gl.c # OpenGL 支持
│ ├── virtio-gpu-pci.c # PCI 设备绑定
│ ├── virtio-gpu-pci-gl.c # GL-PCI 绑定
│ ├── virtio-gpu-udmabuf.c # DMA-BUF 支持
│ ├── virtio-vga.c # VGA 兼容层
│ └── vhost-user-gpu.c # vhost-user GPU
│
└── include/hw/virtio/
└── virtio-gpu.h # GPU 相关类型和接口定义
2.2 架构分层
┌─────────────────────────────────────────┐
│ Guest OS (Linux/Windows) │
│ ┌─────────────────────────────────┐ │
│ │ VirtIO GPU Driver │ │
│ └──────────────┬──────────────────┘ │
└──────────────────┼──────────────────────┘
│ VirtIO Protocol
┌──────────────────┼──────────────────────┐
│ QEMU │ │
│ ┌──────────────▼──────────────────┐ │
│ │ VirtIO Bus (virtio.c) │ │ ◄─ 通用框架层
│ └──────────────┬──────────────────┘ │
│ ┌──────────────▼──────────────────┐ │
│ │ VirtIO GPU Base │ │ ◄─ GPU 基类
│ │ (virtio-gpu-base.c) │ │
│ └──────────────┬──────────────────┘ │
│ ┌───────┴────────┐ │
│ ┌──────▼──────┐ ┌──────▼──────────┐ │
│ │ virtio-gpu.c│ │virtio-gpu-virgl.c│ │ ◄─ 功能实现层
│ │ (2D) │ │ (3D/Virgl) │ │
│ └─────────────┘ └──────┬──────────┘ │
│ │ │
│ ┌────────▼─────────┐ │
│ │ virglrenderer │ │ ◄─ 渲染后端
│ │ (host lib) │ │
│ └──────────────────┘ │
└─────────────────────────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ Host GPU (OpenGL/Vulkan) │
└─────────────────────────────────────────┘
3. 核心文件功能详解
3.1 hw/virtio/virtio.c - VirtIO 核心框架
职责:
- 定义所有 VirtIO 设备的基类
VirtIODevice - 实现 VirtQueue 管理(virtqueue 的创建、删除、通知机制)
- 处理设备特性协商(feature negotiation)
- 管理设备状态机(reset、init、ready)
- 提供配置空间访问接口
关键数据结构:
struct VirtIODevice {
DeviceState parent_obj;
uint8_t status;
uint8_t isr;
uint16_t queue_sel;
uint64_t guest_features;
uint64_t host_features;
// ... VirtQueue 管理
};
3.2 hw/display/virtio-gpu-base.c - GPU 基础功能
职责:
- 实现 GPU 设备的基础操作
- 管理 scanout(输出显示头)
- 处理 EDID 信息
- 显示信息查询
关键函数:
void virtio_gpu_base_reset(VirtIOGPUBase *g);
void virtio_gpu_base_fill_display_info(...);
3.3 hw/display/virtio-gpu.c - 2D 图形功能
职责:
- 实现 2D 资源管理
- 处理 2D 命令(RESOURCE_CREATE_2D, TRANSFER_TO_HOST_2D)
- CPU 软件渲染路径
- 光标管理
核心流程:
- Guest 创建 2D 资源
- 分配 backing store(内存页)
- 数据传输(guest → host)
- Pixman 软件渲染
- 更新显示
3.4 hw/display/virtio-gpu-virgl.c - 3D 加速核心
这是本文档的重点文件,实现了基于 virglrenderer 的硬件加速 3D 渲染。
3.4.1 关键数据结构
struct virgl_gpu_resource {
struct virtio_gpu_simple_resource res; // 继承基础资源
VirtIOGPU *g; // 指向设备实例
#ifdef HAVE_VIRGL_RESOURCE_BLOB
MemoryRegion *region; // blob 资源的内存映射区域
#endif
enum virgl_gpu_resource_type type; // 资源类型
uint32_t scanout_id; // 关联的 scanout ID
uint32_t overlay_id; // overlay 层 ID
};
3.4.2 资源管理
资源生命周期:
创建 (CREATE_RESOURCE_2D/3D/BLOB)
↓
绑定内存 (ATTACH_BACKING)
↓
上下文关联 (CTX_ATTACH_RESOURCE)
↓
使用 (TRANSFER, SUBMIT_3D)
↓
解除关联 (CTX_DETACH_RESOURCE)
↓
解绑内存 (DETACH_BACKING)
↓
销毁 (RESOURCE_UNREF)
关键函数:
- 资源创建
static void virgl_cmd_create_resource_3d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
// 1. 解析 guest 命令
// 2. 创建 virgl_gpu_resource
// 3. 调用 virgl_renderer_resource_create()
}
- Blob 资源(新特性)
static void virgl_cmd_resource_create_blob(...)
{
// 支持两种模式:
// - USE_USERPTR: 直接映射 guest 物理页(零拷贝)
// - 传统 IOV: scatter-gather 内存映射
}
3.4.3 3D 上下文管理
上下文(Context) 是 OpenGL/Vulkan 状态的容器。
static void virgl_cmd_context_create(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
// 创建 virgl 渲染上下文
// 支持多上下文并行
#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS
// 可选:支持上下文初始化标志(如 Vulkan)
#endif
}
3.4.4 命令提交与执行
3D 命令流处理:
static void virgl_cmd_submit_3d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
// 1. 从 guest 读取命令缓冲区
// 2. 处理 fence(同步点)
// 3. 提交给 virgl_renderer_submit_cmd2()
// 4. virglrenderer 解析并执行 OpenGL 命令
}
命令分发器:
void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
switch (cmd->cmd_hdr.type) {
case VIRTIO_GPU_CMD_CTX_CREATE:
virgl_cmd_context_create(g, cmd);
break;
case VIRTIO_GPU_CMD_SUBMIT_3D:
virgl_cmd_submit_3d(g, cmd);
break;
// ... 30+ 命令类型
}
}
3.4.5 Scanout 与显示输出
设置 Scanout(主显示平面):
static void virgl_cmd_set_scanout_blob(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
// 1. 验证 scanout ID 和资源
// 2. 获取渲染后的纹理
// 3. 导出 DMA-BUF 文件描述符
// 4. 更新 QEMU 显示系统
// 5. 标记资源类型为 SCANOUT
}
Overlay 支持(多层合成):
static void virgl_cmd_set_overlay_blob(...)
{
// 支持视频叠加层、字幕等
// 包含 alpha、zpos、blend mode 等属性
}
3.4.6 Fence 同步机制
Fence 用于 GPU 操作的同步和完成通知。
同步架构:
Guest Driver
│
├─ Submit Command + Fence ID
│
▼
VirtIO GPU (QEMU)
│
├─ virgl_renderer_create_fence()
│
▼
virglrenderer
│
├─ OpenGL Fence/Sync
│
▼
Host GPU Driver
│
├─ Fence Complete Callback
│
▼
QEMU Fence Handler
│
├─ Write to pipe
│
▼
Fence Event Loop
│
├─ Notify Guest (interrupt)
实现细节:
// Fence 读写管道(异步通知)
static int virtio_gpu_virgl_fence_read(VirtIOGPU *g, uint64_t *value);
static int virtio_gpu_virgl_fence_write(VirtIOGPU *g, uint64_t value);
// Fence 事件处理
static void virtio_gpu_virgl_fence_event(void *opaque)
{
// 从管道读取完成的 fence
// 在 fenceq 中查找对应命令
// 发送响应给 guest
}
支持两种 Fence 模式:
-
全局 Fence(传统)
- 所有上下文共享 fence 队列
-
Per-Context Fence(高级)
struct context_fence { uint32_t ctx_id; uint64_t queue_id; uint64_t fence_id; uint32_t ctx_fence; };- 每个上下文独立的 fence
- 支持多队列并行
3.4.7 内存映射与 DMA-BUF
Blob 资源映射:
static void virgl_cmd_resource_map_blob(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
// 1. 调用 virgl_renderer_resource_map() 获取 host 指针
// 2. 创建 MemoryRegion
// 3. 映射到 guest 地址空间
// 4. 返回映射信息给 guest
}
零拷贝优化(USERPTR):
// 在 blob 创建时直接使用 guest 物理页
virgl_args.guest_blob_mapped = vres->res.pfns_mapped;
// virglrenderer 直接访问 guest 内存,无需中间拷贝
3.4.8 Virglrenderer 回调接口
QEMU 向 virglrenderer 提供的回调函数:
static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = {
.version = 1,
.write_fence = virgl_write_fence, // Fence 完成通知
.create_gl_context = virgl_create_context, // 创建 GL 上下文
.destroy_gl_context = virgl_destroy_context, // 销毁 GL 上下文
.make_current = virgl_make_context_current, // 切换上下文
#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
.get_egl_display = virgl_get_egl_display, // 获取 EGL 显示
.write_context_fence = virgl_write_context_fence, // 上下文 fence
#endif
};
OpenGL 上下文管理:
static virgl_renderer_gl_context
virgl_create_context(void *opaque, int scanout_idx,
struct virgl_renderer_gl_ctx_param *params)
{
// 通过 QEMU 显示后端创建 GL 上下文
// 返回 context handle 给 virglrenderer
ctx = dpy_gl_ctx_create(g->parent_obj.scanout[scanout_idx].con, &qparams);
return (virgl_renderer_gl_context)ctx;
}
4. 数据流分析
4.1 3D 渲染数据流
┌─────────────────────────────────────────────┐
│ Guest Application (OpenGL/Vulkan) │
└──────────────┬──────────────────────────────┘
│
┌──────────────▼──────────────────────────────┐
│ Guest GPU Driver (Mesa/Virgl) │
│ - 编码 OpenGL 命令为字节流 │
│ - 管理资源 ID 映射 │
└──────────────┬──────────────────────────────┘
│ VirtIO GPU Protocol
┌──────────────▼──────────────────────────────┐
│ QEMU: virtio-gpu-virgl.c │
│ - 接收命令队列 │
│ - virgl_cmd_submit_3d() │
└──────────────┬──────────────────────────────┘
│
┌──────────────▼──────────────────────────────┐
│ virglrenderer (Host User Library) │
│ - 解码命令流 │
│ - 转换为 host OpenGL 调用 │
└──────────────┬──────────────────────────────┘
│
┌──────────────▼──────────────────────────────┐
│ Host OpenGL Driver (Mesa/Proprietary) │
└──────────────┬──────────────────────────────┘
│
┌──────────────▼──────────────────────────────┐
│ Host GPU Hardware │
└─────────────────────────────────────────────┘
4.2 显示更新流程
┌─────────────────────────────────────────┐
│ 1. Guest 渲染完成 │
│ glFlush() / vkQueueSubmit() │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ 2. SET_SCANOUT_BLOB │
│ - 设置 scanout 资源 │
│ - 导出 DMA-BUF FD │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ 3. RESOURCE_FLUSH │
│ - dpy_gl_update_fenced() │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ 4. QEMU Display Backend │
│ - GTK/SDL/Spice │
│ - 纹理 blit 到窗口 │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ 5. Host Window System │
│ - X11/Wayland compositor │
└─────────────────────────────────────────┘
5. 关键特性
5.1 Blob Resources(现代化资源管理)
传统资源 vs Blob 资源:
| 特性 | 传统资源 | Blob 资源 |
|---|---|---|
| 内存分配 | Host 分配 | Guest/Host 协商 |
| 映射方式 | IOV scatter-gather | 直接 IOV |
| 零拷贝 | 不支持 | 支持 |
| 使用场景 | OpenGL 纹理/缓冲区 | Vulkan、视频编解码、DRM |
Blob 类型:
#define VIRTIO_GPU_BLOB_MEM_GUEST 1 // Guest 分配的内存
#define VIRTIO_GPU_BLOB_MEM_HOST3D 2 // Host 3D 引擎分配
#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST 3 // 混合模式
5.2 Capset(能力集)
Capset 用于协商 guest 和 host 支持的渲染特性。
int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g)
{
// 支持的 Capset:
// - VIRGL: OpenGL ES 渲染
// - VIRGL2: OpenGL 核心
// - VENUS: Vulkan 支持
// - DRM: 原生 DRM API
}
5.3 多平面与 Overlay
支持视频播放、UI 合成等高级场景:
// Overlay 属性
vres->res.alpha = so.alpha; // 透明度
vres->res.pixel_blend_mode = so.pixel_blend_mode; // 混合模式
vres->res.zpos = so.zpos; // Z 顺序
vres->res.x_coord = so.x_coord; // 位置
vres->res.y_coord = so.y_coord;
vres->res.scale_width = so.scale_width; // 缩放
vres->res.scale_height = so.scale_height;
6. 初始化流程
int virtio_gpu_virgl_init(VirtIOGPU *g)
{
// 1. 设置渲染器标志
flags = VIRGL_RENDERER_ASYNC_FENCE_CB | VIRGL_RENDERER_THREAD_SYNC;
// 2. 初始化 virglrenderer
virgl_renderer_init(g, flags, &virtio_gpu_3d_cbs);
// 3. 创建 fence 通知管道
virtio_gpu_virgl_init_pipe(g);
// 4. 注册 fence 事件处理器
qemu_set_fd_handler(g->read_pipe,
virtio_gpu_virgl_context_fence_event, NULL, g);
// 5. 启动 fence 轮询定时器
g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL,
virtio_gpu_fence_poll, g);
return 0;
}
7. 性能优化
7.1 异步 Fence 处理
static bool use_async_cb = true;
// 异步模式下,fence 回调在独立线程执行,减少主循环延迟
7.2 零拷贝路径
// USERPTR blob 直接映射 guest 物理内存
virtio_gpu_create_mapping_pfns(...);
virgl_args.guest_blob_mapped = vres->res.pfns_mapped;
7.3 批量刷新
static void virgl_cmd_resource_flush_batch(...)
{
// 一次性刷新多个平面(primary + overlays)
dpy_gl_flush_planes_batch(con, planes, plane_count, fence_id);
}
8. 调试与统计
8.1 性能统计
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
g->stats.req_3d++; // 3D 请求计数
g->stats.bytes_3d += size; // 3D 数据传输量
}
8.2 Trace Points
文件使用了 trace 系统记录关键操作:
trace_virtio_gpu_cmd_res_create_3d(resource_id, format, width, height, depth);
trace_virtio_gpu_cmd_ctx_submit(ctx_id, size);
trace_virtio_gpu_fence_ctrl(fence_id, cmd_type);
9. 参考资料
10. 总结
virtio-gpu-virgl.c 是 QEMU VirtIO GPU 3D 加速的核心实现,它通过以下机制实现高性能虚拟化图形:
- 分层架构:清晰的框架层、设备层、功能层分离
- virglrenderer 集成:利用成熟的渲染库实现 OpenGL 加速
- 高效同步:异步 fence 机制减少延迟
- 零拷贝优化:blob 资源消除内存拷贝
- 丰富特性:支持 Vulkan、DRM 等现代 API
这种设计使得虚拟机可以接近原生性能运行图形应用,同时保持良好的隔离性和可移植性。
2254

被折叠的 条评论
为什么被折叠?



