背景

随着虚拟化技术如模拟器,容器化等技术等发展,在安卓云游戏/云手机场景中,可以在服务宿主侧虚拟出更多更小颗粒度的 Android 实例。其中比较核心的技术是图形虚拟化技术,如何最大限度利用宿主侧的 GPU 资源进行渲染和编码,不考虑软编等利用 CPU 资源进行渲染编码是因为效率带来的延迟问题。

Linux 图形栈

先看一个比较通用的 linux 图形栈:

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(1)

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(2)

包含 Wayland 比较主流的所有图像栈变得异常复杂:

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(3)

每种应用的图像数据流都比较复杂,但大致流线是:应用(显示 Client)->(显示 Server)->OpenGL/EGL->Mesa 3D->libDRM->(内核)DRM->GPU 驱动。

Android 图形栈

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(4)

以 SurfaceFlinger 为核心,维护了所有 app 窗口的交叠覆盖关系:

综合 Linux 图形栈和 Android 图形栈可以发现在底层都是基于 drm 实现,实现硬编方案的核心思想就是渲染和编码都利用宿主侧的 GPU,并且渲染和编码 Zero-copy,所以有两类技术:

  1. virto-gpu 技术将 OpenGLES 命令导出(virgl)之后再反过来调用宿主侧的 virglrenderer,又将其翻译回 OpenGL 和 GLSL,然后再调用宿主的 OpenGL,这部分技术代表是 Qemu 方案。使用假的抽象 GPU。在抽象层 GPU 层进行拦截,并调用宿主侧的 GPU。

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(5)

  1. 直接导出 DRM 句柄,利用 DRM 的 Zero-copy 的特性进行渲染和编码,渲染和编码通过 IPC 技术传递 fd,这部分代表是 AiC(Android in Container)容器化技术。
  2. 以上两类技术由于最终都是 drm 图像 buffer,故都可以通过 IPC 技术在渲染进程和编码进程之间通过 IPC 传递。渲染进程一般在容器/模拟器内,编码进程一般在容器外。
多媒体编解码相关

以上图形栈涉及显示和渲染,在云游戏的场景中,还需考虑编码设计的技术栈。就编码而言:

如果想要在 Android 内使用硬件编解码,要么实现一套 OMX 到 ffmpeg 的转换翻译,要么厂商对接实现 OMX 的 vendor 驱动,否则很难在 Android(容器或模拟器中)内硬件编码。比较合理的方式是导出 libdrm 的 FD,渲染和编码在不同的进程中,编码选择在 host 中调用 ffmepg 或者 vender 的编码 API 进行编码,进而完成整个推流。

方案

硬编目前精力放在处理进程间传递图像 prime FD,还有相应的音频,双向 input 通信等。采用统一的 Spice 协议或者改造的 spice 协议统一 Android 虚拟化和容器化整合方案。

spice 协议

SPICE,Simple Protocol for Independent Computing Environment,是 Redhat 公司开源的一套远程桌面虚拟化协议,旨在提供商业级别的远程桌面体验。Spice 协议具有如下优点:

  1. 开源:易于扩展和功能定制;
  2. 跨平台:Windows/Linux/Mac OS 平台全兼容;
  3. 支持外接设备:除常用 USB 设备外,打印机和扫描仪等设备也能在远程使用;
  4. 丰富的媒体支持:包括视频、音频、图像;
  5. 更小的带宽占用:Spice 里内置图像压缩算法,有效减少数据传输时的带宽占用;
  6. 更安全的数据传输:Spice 可以使用 OpenSSL 加密传输数据。
概述

包含四个部分:协议、客户端侧、服务端侧和虚拟机侧。其中:

  1. 协议:是客户端侧、服务端侧和虚拟机侧三个部分交互时所遵循的准则;
  2. 客户端:负责接收并转换虚拟机数据,以及发送用户输入数据到虚拟机,从而使得用户能够与虚拟机进行交互;
  3. 服务端:集成在 Hypervisor 内部的一个用户层组件,使得 Hypervisor(如 QEMU)支持 Spice 协议;
  4. 虚拟机侧:指所有部署在虚拟机内部的必需组件,如 QXL 驱动、Spice Agent 等。

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(6)

图像流

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(7)

上图示意了整个图像从 Guest OS 到客户端图像传输通路,其中:

QXL 设备的其他功能包括:

VDagent 命令流

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(8)

Spice Server

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(9)

Spice 协议改造

Spice Client 收到 Spice Server 端发过来的 main,display,playback 等通道后:

  1. 显示通道在默认的 display 上调用 GTK widget 相关组件将图像画在屏幕上。
  2. 获取 playback 音频数据,通过 gstreamer 的 pipeline,调用 alsa 播放音频。
  3. 其他鼠标键盘等处理,不作任何处理。

为适合我们的推流改造如下:

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(10)

对原协议改动比较大的:

  1. Display Channel 通道,这部分在获取到 FD 之后,原本画在 GTK 的流程通过 HwFrame 适配模块,转换成 RTC 编码所需的数据源(YUV 或者 RGBA)。
  2. Main Channel 通道增加 VDAgent 类型增加自定义类型传输 RTC 远程调用指令,反向通过封装将 RTC 的事件和 DataChannel 传递给 GameService(游戏管理服务进程)。
Spice 协议抓包

可以通过 socat 等工具代理 domain socket 来分析 spice 协议,对一个完整的 Spice 协议交互流程,通过 TCP dump 抓取 wireshark 日志如下:

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(11)

先通过 main channel 建立连接,认证,然后依次建立 Spice Display, Spice PLAYBACK, SPICE RECORD, SPICE INPUT 等通道,最后通过各通道发送特定的消息。

这里重点关注以下:

  1. Main Channel 的 VDAgent 通道,在 CLIPBOARD 和 File_XFER 之外添加 VD_AGENT_VENDOR_DATA,为远程 gRPC 调用,接收 android 侧的封装数据。

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(12)

  1. Display Channel,

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(13)

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(14)

  1. Playback Channel,android 系统的声音消息,如音量变化,声音开始与停止等。

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(15)

QEMU 方案

QEMU 方案可以直接复用社区的 qemu kvm 方案,除了针对不同硬件导出不同的 fd 之外。

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(16)

AiC 容器

相比于虚拟化,容器化的特殊之处在于 qemu 已经集成 Spice Server 组件,虚拟化的容器需要容器外编码的话需要导出音频,视频和控制通道,然后实现一套类似 Spice 协议的架构,为统一兼容性通过增加下图的转发模块 Adapter/SpiceServer,将 IPC 通道再次转发至 Spice 通道,实现 QEMU/AiC 方案的统一。

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(17)

方案参数

在整个整合方案中,有如下因素和参数需考虑:

  1. 模拟器或者容器环境区分。如果导出的 fd 在模拟器和容器方案一致,不需要区分,否则需要通过环境变量或者传入启动参数来区分。
  2. DRM device 指定。在携带 GTK 的版本中需要指定 Display 的 device,移除 Xorg 依赖后需指定 Render node。
  3. 编码显卡硬件指定,由于不同硬件编码不同,在编码模块需要通过当前硬件信息来确定编码方式。
图形导出

从虚机或者容器导出,有两种类型的图形显存的 fd:

KHR_STREAM

渲染到宿主侧的 surface,suface 导出 EGLSTREAM,通过eglCreateStreamKHR和eglGetStreamFileDescriptorKHR导出对应的 EGLStreamKHR 文件描述符,适用于 NVIDIA 显卡。消费侧通过eglStreamConsumerAcquireKHR导出对应的 stream,但编码不能直接使用 stream 类型, CUDA 提供了 OpenGL 与 CUDA 互操作 API,将 texture 或者 render buffer 绑定 CUDA 资源之后,CuGraphicsSubResourceGetMappedArray映射出 CUarray 指针供编码器使用。

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(18)

MESA_IMAGE

渲染到宿主侧的 texture,texture 导出为 DMA buffer,通过eglExportDMABUFImageQueryMESA,eglExportDMABUFImageMESA导出,适用于 AMD/Intel 显卡。消费侧通过此创建 EGLImage, 并绑定 2D 纹理,将此纹理的 textureID 传递给编码器 VAAPI 通过此编码器进行编码。

stream流在开发中的应用(基于SPICE协议的硬编推流整合方案在云游戏中的应用)(19)

优化与演进代码重构

随着支撑的方案类型增加,整个工程在满足功能情况下逐渐难以维护,通过 C 重写各个模块,将 HwFrame 模块抽象,对日志/SRE 各模块划分重构,将工程模块化。

移除 Xorg

Xorg 作为 X(11)协议中的 Server 的实现,Spice Client 的通过调用 GTK API 端做 client,存在弊端:

  1. 默认会将导出的 fd,通过 GTK widget 画在默认的 Display 上,但是实际推流过程并不需要这个步骤。
  2. 部署 Xorg 也增加了复杂度。

需要将依赖和 GTK 的组件移除,降低组件依赖复杂性和性能消耗。

具体而言:

  1. Display channel 相关的 GTK widget 依赖移除,。
  2. 替换原有 Display,对 Nvidia,getPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, (EGLNativeDisplayType)dev[num], NULL)导出。
  3. 替换原有 Display,对 VAAPI 的 AMD 或者 Intel 显卡,由于使用的 mesa 图形栈,getPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA导出,需要注意的一点是在 VAAPI 接口中,将初始化用的 Display 换成 DRM 导出。

#if ENABLE_GTK int vaapi_init() { x11_display = XOpenDisplay(g_getenv("DISPLAY")); va_display = vaGetDisplay(x11_display); #else int vaapi_init(int drm_fd) { va_display = (uint64_t)vaGetDisplayDRM(drm_fd); g_message("drm_fd:%d va_dpy:%p", drm_fd, va_display); #endif int major_ver, minor_ver; va_status = vaInitialize(va_display, &major_ver, &minor_ver); return 0; }

移除 gstreamer

音频的 pipeline 使用了 gstreamer,这部分依赖可以去掉。

图形转换优化

总体想法就是图像的 Zero-copy,减少在 CPU 与 GPU 之间的拷贝与图形格式之间转换。

编码卡支持

支持主机通过 PCIE 外插硬件编码卡进行硬件编码。

混合硬件编码支持

总体想法就是利用 host 渲染能力,将渲染后的 RGBA 或者 YUV 导出给编码卡,达到最大限度利用渲染资源,提高并发路数的工作。

自升级

通过 Host Gameservice 进程自我升级固件,不依赖整体部署 pod 节点镜像更新,可以灵活实现升级。

监控与 SRE

对系统指标的打点和性能的监控,完善 SRE 等监控体系,治理进程崩溃,卡死,内测泄漏等检测。

其他

整个云游戏的视频流硬编码方案的实现和上线部署离不开跨部门的合作,再次感谢一起将整个方案从开始设计到到上线的内部兄弟团队如基础系统部门 STE,多媒体 RTC 等部门,通过团队协作推动整个方案上线以及后续线上持续优化和治理。

关于我们

作为字节跳动的视频中台部门,视频架构支持了字节全系产品的点播、直播、实时通信、图片、云游戏、多媒体业务发展,目标成为业界多媒体解决方案领导者,构建极致的视频技术/产品服务体验!

视频架构-设备与服务团队聚焦多媒体 IoT/5G 相关领域,孵化能够赋能业务的新场景和核心技术,打造极致的、软硬件结合的技术解决方案,上线了云游戏、云手机、视联网、多屏互动等多款服务,支持了抖音、西瓜等众多内部产品,同时也通过火山引擎提供 toB 服务。欢迎更多同学加入我们,构建行业顶尖的视频创新技术,联系luxuguang@bytedance.com 注明“设备与服务方向”。

参考,