kuanat

kuanat

V2EX 第 634702 号会员,加入于 2023-06-19 11:38:40 +08:00
今日活跃度排名 5997
基于 Go 语言谈软件开发效率
Go 编程语言  •  kuanat  •  100 天前  •  最后回复来自 phoulx
15
Zed Linux vim 模式输入法切换
Zed  •  kuanat  •  122 天前
一个好用的、纯软件的扩展屏方案
分享发现  •  kuanat  •  313 天前  •  最后回复来自 kuanat
2
V2EX 是否会考虑增加专栏功能?
V2EX  •  kuanat  •  349 天前  •  最后回复来自 kuanat
5
分享一些 Go 在全栈开发中的经验
  •  13   
    Go 编程语言  •  kuanat  •  264 天前  •  最后回复来自 GeekGao
    43
    kuanat 最近回复了
    @shalingye #21

    考虑先实现出来吧,就用系统的 api 这样可以覆盖所有情况,延迟和性能的问题先不去处理。

    粗略估计 4k 120hz 10bit 无压缩每帧数据量在 30MB 左右,单帧时间 8.3ms ,单从数据量上来说,如果是通过某种网络协议传输是没有带宽压力的,主要困难是延迟,发送接收涉及编解码。obs 有个 ndi 实现(现在叫 DistroAV ),就是在一台设备上采集,然后通过网络将数据传输到另一台设备上进行编码,可以参考一下它去掉网络开销的延迟水平。



    共享内存的路线,Linux 的实现方式大概是这样的:

    1. Linux 宿主机内核驱动 virtio 实现了 IVSHMEM

    2. Linux 虚拟机或者 windows 虚拟机也通过 virtio 的驱动模块启用 IVSHMEM

    3. 虚拟机和宿主机通过指定相同的物理地址实现内存共享( IVSHMEM 本质是虚拟 PCI 设备)

    4. 虚拟机内的特定应用(你要开发的)将 framebuffer 封装好后写入 IVSHMEM 的特定区域(手动管理)

    5. (可选)宿主机应用通过 IVSHMEM 读取对应的 framebuffer 并做后续处理



    这里可以看到 IVSHMEM 实际只是非常粗糙的共享内存机制,还需要在它的基础上实现用它完成 fb 数据交换。之前提到的 looking-glass 就是实现了一个叫 KVMFR 的模块,在 IVSHMEM 的基础上封装了一个用于 fb 数据交换的接口(硬件设备),同时实现了宿主与虚拟机之间的同步、锁,另外它用来做数据交换的格式是 dma-buf ,这样宿主机上的窗口合成器可以直接使用。之后,虚拟机的采集应用( obs/ffmpeg/系统采集)直接将数据写入 KVMFR 。

    如果你要在 windows 实现类似的功能,需要把 vmbus 当作 IVSHMEM ,然后在上面实现一个 windows 版本的 KVMFR 。



    估计这样表述应该就清楚了,由于我对 windows 不是特别了解,所以上面的方案不一定正确。
    @kuanat #19
    @shalingye #16

    中间发不出来的一段是关于如何获取 framebuffer 的。通过系统 api 会有二次复制的延迟,通过显卡特定 api 更合适。
    @kuanat #18
    @shalingye #16


    最后再回到之前说的共享内存方案。实际上 framebuffer 的数据结构某种程度上说是硬件相关的。也就是说,即便在虚拟机和宿主机之间通过虚拟设备共享了内存,一方面要对接这个虚拟内存的读写接口,另一方面需要将 framebuffer 封装成一种统一的格式。这样在宿主机上,用于显示虚拟机内容的窗口可以直接将 framebuffer 提交给窗口管理器进行合成,即再次 DMA 到显卡。

    如果我说得不是很清楚的话,可以参考 https://looking-glass.io/ 这个项目,它的核心实现是 KVMFR https://github.com/gnif/LookingGlass/blob/master/module/kvmfr.c 这个模块,基于 IVSHMEM 完成我之前说的流程。理论上 windows 上实现相同效果的原理是一样的。
    @kuanat #17
    @shalingye #16

    我之前回复的是满足第二个要求的方法。先不考虑虚拟机里的视频信号从哪里来的,假设你已经获得了实时 framebuffer 流,可以走网络协议,同时由于宿主机和虚拟机在一起,也可以走共享内存。技术上说,所有走网络协议的方案因为存在编解码、封装,都不可能比直接内存共享延迟更低。就拿 kvm 常见的虚拟化方案来说,SPICE 是个网络协议,但与 qxl 搭配的时候,使用的是共享内存。

    从原理上说,kvm 这边直接用 SPICE 就可以了。我搜了一下 vmbus 的文档,虽然提到了共享内存,但我感觉用它来共享 framebuffer 需要做的工作还很多。
    @shalingye #16

    如果我没理解错的话,你的需求是这样的:宿主机上运行的虚拟机,然后宿主机的某个客户端窗口,显示虚拟机的视频输出内容。

    为了达到目标性能要求,一方面需要虚拟机本身能够实现高分辨率高刷新率,另一方面这个达标的显示输出能够在宿主机上正确还原,中间的通信延迟要足够低(输入设备还在宿主机上并没有直通到虚拟机)。



    为了达到第一个要求,一般有两个方案:

    1. 使用半虚拟化驱动设备,比如 qxl ,virgl 还有一些都属于这种,在虚拟机里面使用虚拟的显卡设备,这个设备会将渲染指令传递给宿主机,通过宿主机执行后再将结果传回虚拟机

    2. 直通物理显卡或者利用 sriov 直通物理显卡虚拟出来的显卡

    我对 windows 不熟悉,猜测 windows 的几个实现原理上应该都是上面两个思路。



    不知道触发了什么关键词,我二分一下拆开回复。
    @kuanat #68

    vscode 不行哈哈,原因就是 #73 说的。
    Linux 这边 virtio 也有类似的需求和实现方案。

    我个人的理解是:

    - 如果虚拟机内部是虚拟的 gpu ,那么就可以直接共享内存,宿主机直接访问虚拟机内虚拟 gpu 的 framebuffer

    - 如果虚拟机内部有直通的 gpu ,那就只能从 framebuffer 入手抓取视频源(比如 nvfbc ),然后再共享给宿主机

    应该不存在比直接内存映射更高效的 IPC 方式了。
    我认为是 vscode 的锅,因为我的印象里这个功能 gopls 很早就有了,不过我现在主力是 neovim ,待我验证一下。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1063 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 18:07 · PVG 02:07 · LAX 11:07 · JFK 14:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.