Guest → QEMU → Virglrenderer 调用逻辑分析

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:
        
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeeplyMind

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值