如果说 vrend 是"翻译",Venus 就是"转发"。Venus 不试图理解每条 Vulkan 命令的图形语义,而是把 Guest 的 Vulkan 调用序列化成协议字节流,在 Host 端几乎一比一地重放。这套"薄转发"思路让 Vulkan 虚拟化的开销做到极低。本章拆解src/venus/(vkr_*)。
10.1 设计哲学:协议转发而非 API 翻译
- capset:
VIRTGPU_DRM_CAPSET_VENUS (4); - 协议:
VK_MESA_venus_protocol——一个把 Vulkan API 调用编码成字节流的 Khronos 风格协议; - Guest 侧:Mesa 的 venus Vulkan 驱动,把应用的
vkXxx()调用编码进 venus ring; - Host 侧:virglrenderer 的
vkr_*反序列化,调用真实的 Host VulkanICD(RADV/ANV/turnip/NVIDIA 等)。
对比 vrend:
| 维度 | vrend(OpenGL) | venus(Vulkan) |
|---|---|---|
| 思路 | 翻译(TGSI→GLSL、命令语义翻译) | 转发(序列化/反序列化) |
| Host 依赖 | Host GL | Host Vulkan ICD |
| 开销 | 较高(要理解语义) | 极低(近乎重放) |
| 着色器 | TGSI→GLSL | SPIR-V 直接透传 |
因为 Vulkan 本身就是"显式、薄驱动"的 API,它天然适合序列化转发——这正是 Venus 能高性能的根本原因。
Guest 前端栈:Guest 里跑的是 Mesa 的venus 虚拟驱动(不对应真实硬件),把 Vulkan 调用按VK_MESA_venus_protocol编码经 virtio-gpu 送到 Host,由vkr_*反序列化后重放到真实 Vulkan ICD:
10.2 对象模型:一一对应的影子对象
Venus 为几乎每种 Vulkan 对象都建了一个vkr_*影子类型,维护 Guest 句柄 ↔ HostVkXxx的映射:
| 文件 | 对应 Vulkan 对象 |
|---|---|
vkr_instance.c | VkInstance |
vkr_physical_device.c | VkPhysicalDevice |
vkr_device.c | VkDevice(逻辑设备) |
vkr_queue.c | VkQueue+ 同步 |
vkr_command_buffer.c | VkCommandBuffer |
vkr_device_memory.c | VkDeviceMemory |
vkr_buffer.c/vkr_image.c | VkBuffer/VkImage |
vkr_pipeline.c | VkPipeline/ layout |
vkr_descriptor_set.c/vkr_descriptor_heap.c | 描述符集/池 |
vkr_render_pass.c | VkRenderPass/ framebuffer |
vkr_query_pool.c | VkQueryPool |
vkr_acceleration_structure.c | 光线追踪加速结构 |
这些对象由vkr_context.c统一管理生命周期,vkr_renderer.c是后端总入口。
10.3 传输层:ring / cs / transport
Venus 的命令不走 virgl 那种"每条 header+body"格式,而是通过专用的环形缓冲高效传输:
vkr_ring.c:venus 的 ring buffer,Guest 生产、Host 消费,减少边界穿越;vkr_cs.c:command stream 的编解码(decoder/encoder),把字节流还原成一次次 Vulkan 调用及其参数;vkr_transport.c:底层传输与 ring 的接入。