1. 概述
本文分析虚拟机图形加速的完整调用链路:从 Guest OS 中的应用程序发起图形请求,经过 virtio-gpu 驱动、QEMU 虚拟机管理器,最终到达 virglrenderer 库执行实际渲染的全过程。
1.1 整体架构
┌─────────────────────────────────────────────────────────────┐
│ Guest OS │
│ ┌─────────────┐ │
│ │ Application │ (OpenGL/Vulkan API) │
│ └──────┬──────┘ │
│ │ │
│ ┌──────▼──────────────────┐ │
│ │ Mesa / Vulkan Driver │ │
│ │ (virgl, venus) │ │
│ └──────┬──────────────────┘ │
│ │ ioctl() │
│ ┌──────▼──────────────────┐ │
│ │ virtio-gpu Kernel │ │
│ │ Driver (DRM/KMS) │ │
│ └──────┬──────────────────┘ │
└─────────┼──────────────────────────────────────────────────┘
│ virtio ring (virtqueue)
│
┌─────────▼──────────────────────────────────────────────────┐
│ QEMU │
│ ┌──────────────────────────────┐ │
│ │ virtio-gpu PCI Device │ │
│ │ (hw/display/virtio-gpu.c) │ │
│ └──────┬───────────────────────┘ │
│ │ virgl_renderer_*() │
│ ┌──────▼───────────────────────┐ │
│ │ virglrenderer 库接口层 │ │
└──┼─────────────────────────────┼───────────────────────────┘
│ │
│ libvirglrenderer.so │
│ │
┌──▼──────────────────────────────▼───────────────────────────┐
│ Virglrenderer Library │
│ ┌──────────────────┬──────────────────┬─────────────────┐ │
│ │ vrend (OpenGL) │ venus (Vulkan) │ drm │ │
│ └────────┬─────────┴────────┬─────────┴────────┬────────┘ │
└───────────┼──────────────────┼──────────────────┼───────────┘
│ │ │
┌───────▼──────┐ ┌───────▼──────┐ ┌──────▼──────┐
│ Host OpenGL │ │ Host Vulkan │ │ Host DRM │
│ Driver │ │ Driver │ │ │
└──────────────┘ └──────────────┘ └─────────────┘
2. 核心调用流程详解
2.1 初始化阶段
阶段 1: QEMU 启动 virglrenderer
当 QEMU 启动虚拟机时,如果配置了 virtio-gpu 设备,会执行以下初始化:
// QEMU 侧伪代码
virgl_renderer_callbacks cbs = {
.version = 4,
.write_fence = qemu_write_fence, // fence 回调
.write_context_fence = qemu_write_ctx_fence, // 上下文 fence
.create_gl_context = qemu_create_gl_context, // GL 上下文创建
.destroy_gl_context = qemu_destroy_gl_context,
.make_current = qemu_make_current,
.get_drm_fd = qemu_get_drm_fd, // 获取 DRM fd
.get_server_fd = qemu_get_server_fd, // Venus 专用
.get_egl_display = qemu_get_egl_display // EGL 显示
};
int flags = VIRGL_RENDERER_USE_EGL |
VIRGL_RENDERER_THREAD_SYNC |
VIRGL_RENDERER_ASYNC_FENCE_CB;
// 初始化 virglrenderer
virgl_renderer_init(qemu_cookie, flags, &cbs);
阶段 2: virglrenderer 内部初始化
virgl_renderer_init() 函数执行以下步骤(代码:src/virglrenderer.c:):
int virgl_renderer_init(void *cookie, int flags,
struct virgl_renderer_callbacks *cbs)
{
// 1. 保存回调和状态
state.cookie = cookie;
state.flags = flags;
state.cbs = cbs;
// 2. 初始化资源表(全局资源管理)
virgl_resource_table_init(pipe_cbs);
state.resource_initialized = true;
// 3. 初始化上下文表(全局上下文管理)
virgl_context_table_init();
state.context_initialized = true;
// 4. 初始化窗口系统(EGL/GLX)
if (flags & VIRGL_RENDERER_USE_EGL) {
int drm_fd = cbs->get_drm_fd(cookie);
vrend_winsys_init(flags, drm_fd);
state.winsys_initialized = true;
}
// 5. 初始化 OpenGL 渲染器
if (!(flags & VIRGL_RENDERER_NO_VIRGL)) {
vrend_renderer_init(&vrend_cbs, renderer_flags);
state.vrend_initialized = true;
}
// 6. 初始化 Vulkan 渲染器 (Venus)
if (flags & VIRGL_RENDERER_RENDER_SERVER) {
proxy_renderer_init(&proxy_cbs, flags);
state.proxy_initialized = true;
}
// 7. 初始化 DRM 原生渲染器
if (flags & VIRGL_RENDERER_DRM) {
drm_renderer_init(drm_fd);
state.drm_initialized = true;
}
// 8. 初始化 fence 同步表
virgl_fence_table_init();
state.fence_initialized = true;
return 0;
}
关键数据结构:
struct global_state {
void *cookie; // QEMU 传入的上下文指针
const struct virgl_renderer_callbacks *cbs; // 回调函数表
// 各子系统初始化标志
bool vrend_initialized; // OpenGL 渲染器
bool proxy_initialized; // Vulkan/Venus
bool drm_initialized; // DRM 原生
bool resource_initialized; // 资源管理
bool context_initialized; // 上下文管理
bool fence_initialized; // fence 同步
};
2.2 上下文创建与管理
上下文创建流程(代码:src/virglrenderer.c:216)
int virgl_renderer_context_create_with_flags(
uint32_t ctx_id,
uint32_t ctx_flags,
uint32_t nlen,
const char *name)
{
// 1. 提取 capset_id(决定渲染器类型)
uint32_t capset_id = ctx_flags &
VIRGL_RENDERER_CONTEXT_FLAG_CAPSET_ID_MASK;
struct virgl_context *ctx;
// 2. 根据 capset_id 选择渲染器
switch (capset_id) {
case VIRTGPU_DRM_CAPSET_VIRGL:
case VIRTGPU_DRM_CAPSET_VIRGL2:
// OpenGL 渲染器
ctx = vrend_renderer_context_create(ctx_id, nlen, name);
break;
case VIRTGPU_DRM_CAPSET_VENUS:

最低0.47元/天 解锁文章
2031

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



