本文梳理在 virglrenderer 中新增一个后端设备(backend device)的整体流程与关键设计点,示例参考上游的 DRM native context 与 HSAKMT(ROCm/HSA)两组补丁。
13.1 总体架构
13.1.1 插件式设计
virglrenderer 采用插件式架构:每类设备都是一个自包含模块,通过一组明确定义的接口接入核心框架。这样每个设备可以独立开发、测试,并按需条件编译,互不影响核心渲染器与其他设备。
框架本质上是一个能力路由器(capability router):依据创建 Context 时传入的CAPSET ID,把操作分派到对应的设备实现。路由用switch-case实现,新增设备时只需在关键路由点加一个case分支,扩展方式高度一致、可预测。
- 公开 API 层:向 VMM(QEMU、crosvm 等)提供稳定的
virgl_renderer_*接口。 - 能力路由层:按 Context 创建标志里的 CAPSET ID 把操作分派到具体设备。
- 设备实现:各自独立的模块(VIRGL 走 OpenGL/ES、Venus 走 Vulkan、DRM 走 native context、HSAKMT 走 ROCm/HSA 等)。
- 统一接口:所有设备都实现
virgl_context接口,保证一致性与可组合性。
QEMU 命令行上通过开关选择启用哪些设备,每个开关对应一类 CAPSET:
# drm=on → DRM native context → CAPSET_DRM → 对应设备逻辑# hsakmt=on → HSAKMT → CAPSET_HSAKMT → 对应设备逻辑-devicevirtio-vga-gl,drm=on,hsakmt=on13.1.2 CAPSET ID:设备的主标识
CAPSET ID 是整个设备架构的基石,是贯穿各环节的统一标识:
- 编译期:分隔各设备实现、支撑条件编译、按特性组织代码。
- 初始化期:决定初始化哪些设备、校验设备可用性、配置设备特性、优雅处理初始化失败。
- 运行期:把 Context 创建、能力查询、资源操作路由到正确的设备,支撑多设备共存。
上游实际的 CAPSET ID 取值(见src/drm/drm-uapi/virtgpu_drm.h与src/rocm/hsakmt_device.h):
| 名称 | 值 | 说明 |
|---|---|---|
VIRTGPU_DRM_CAPSET_VIRGL | 1 | OpenGL/ES(vrend) |
VIRTGPU_DRM_CAPSET_VIRGL2 | 2 | OpenGL/ES v2 |
VIRTGPU_DRM_CAPSET_GFXSTREAM_VULKAN | 3 | gfxstream Vulkan |
VIRTGPU_DRM_CAPSET_VENUS | 4 | Venus(Vulkan proxy) |
VIRTGPU_DRM_CAPSET_CROSS_DOMAIN | 5 | cross-domain |
VIRTGPU_DRM_CAPSET_DRM | 6 | DRM native context |
VIRGL_RENDERER_CAPSET_HSAKMT | 8 | HSAKMT(ROCm/HSA) |
新增设备时,为其分配一个尚未占用的 CAPSET ID,并在 guest 侧驱动与 host 侧渲染器之间保持一致。
13.1.3 依赖倒置与接口隔离
架构遵循 SOLID 中的依赖倒置与接口隔离:高层核心只依赖抽象契约,不依赖具体实现;具体设备实现该契约,且可独立演进。
13.1.4 三阶段集成
设备集成通常按三个阶段推进,确保依赖清晰、关注点分离: