Hacker News 中文摘要

RSS订阅

Triton:QEMU的DirectX 11驱动程序 -- Triton: DirectX 11 Driver for QEMU

文章摘要

Triton是一款为QEMU虚拟机开发的全新Windows驱动程序,与Neptune协议层配合,为Windows客户机提供完整的DirectX 11图形加速支持,实现了在QEMU虚拟机上运行现代图形应用的目标。

文章总结

文章核心内容中文重述

标题:Triton:QEMU的DirectX 11驱动程序

背景与目标

此前我们推出了Neptune——一个用于VirtIO的Direct3D协议转发层,它能够将Direct3D API调用序列化后跨虚拟机边界传输,使Linux客户机中的Wine游戏在Linux宿主机上运行速度比直接在客户机中使用DXVK更快。但这只是铺垫,我们的真正目标是:为Windows客户机提供现代图形加速。现在,我们通过构建名为Triton的全新Windows驱动程序实现了这一目标,它与Neptune配合,为QEMU虚拟机带来了完整的DirectX 11支持。

Triton是什么?

有人可能会问:既然Neptune能序列化Direct3D API调用,而Windows本身就使用Direct3D,那是不是已经完成了?答案是可以部分实现。Neptune Mesa驱动构建了d3d11.dlldxgi.dll,完整实现了Direct3D API集。如果将这些文件放在游戏可执行文件旁边,Windows会加载它们而非自带的驱动,这样某些游戏就能运行。但这种方法有几个缺点:

  1. 性能不佳:窗口合成器(DWM)将帧视为图像,需要使用CPU位块传输将GPU图像缓冲区复制到正确窗口位置,无法获得流畅的桌面体验。
  2. 系统文件不可替换d3d11.dlldxgi.dll是Windows核心组件,无法替换系统文件。许多带反作弊系统的游戏会检测这种修改。
  3. 用户体验差:需要为每个需要图形加速的应用程序复制文件。

正确的方法不是实现DirectX API,而是实现DirectX DDI(设备驱动程序接口)。

DDI(设备驱动程序接口)

在Windows中,应用程序与系统Direct3D和DXGI库通信。d3d11.dll负责复杂的状态跟踪,将更规范化的命令流发送给实现DDI的用户模式驱动(UMD)。UMD通过DXGI与内核模式驱动(KMD)通信,KMD由图形供应商实现以驱动实际硬件(在我们的案例中是虚拟硬件)。

挑战在于:实现具有DirectX DDI接口的UMD,并建立与KMD的私有接口,该KMD与VirtIO设备通信。

幸运的是,第二部分已经解决。anonymix007和arehnman各自独立开发了用于Venus(Vulkan)的KMD。由于Neptune以Venus为模型,高层内核接口(用于DMA、命令缓冲区等)非常相似,UMD和KMD之间的接口完全相同。我们最终选择了anonymix007的分支作为基础。

DXBC(DirectX字节码)

DXBC是微软着色器编译器(FXC)发出的中间代码格式,是DirectX 12之前的旧格式,由HLSL编译而来。由于Triton充当从DDI到API的反向转换,它不需要反汇编和转换着色器字节码,这在复杂性和兼容性方面是巨大优势。

然而,问题在于编译器(FXC)发出DXBC字节码时附带其他元数据,d3d11.dll会使用这些元数据。当调用DDI时,只传递字节码。这意味着要有效进行"反向转换"回API调用,我们需要通过解释字节码来重新构建所有元数据。虽然最终仍会原样传递字节码,但由于看不到原始DXContainer文件,我们必须合成宿主机DirectX渲染器期望的字段。这是实现中最薄弱、最容易出错的部分。

宿主机渲染器

整个流程如下: 1. 应用程序向系统库发出DirectX和DXGI API调用 2. 系统库通过DDI调用调用Triton 3. Triton DDI将原始DXBC字节码转换回DXContainer,并向Neptune发出DirectX和DXGI API调用 4. Neptune UMD序列化API调用,通过KMD管理的环形缓冲区传递 5. KMD使用VirtIO接口向宿主机发送命令 6. QEMU宿主机处理命令并将Neptune调用传递给virglrenderer 7. virglrenderer中的Neptune宿主机模块反序列化API调用并转发给宿主机端DirectX实现 8. 宿主机DirectX实现渲染帧

在Wine的Neptune中,我们分叉了DXVK以支持将交换链图像导出为DMAbuf资源。但在Triton中,我们发现宿主机端交换链处理是个错误。在Windows上,DXGI是系统组件,与UMD通信,处理后台缓冲区创建、帧节奏、模式切换等。UMD通常不对DXGI给予特殊处理,因此我们的DDI调用"反向转换"回API调用的方法对DXGI效果不佳。桌面合成器(DWM)操作共享纹理,这意味着除了DMAbuf导出,我们还需要在DXVK中实现DMAbuf导入。一旦实现导入和导出,就不再需要宿主机端交换链逻辑,因此我们将所有交换链逻辑移入客户机Neptune驱动。

macOS支持

在macOS上运行virglrenderer存在挑战,但既然Venus现在能在macOS上运行,大部分后端挑战已解决。剩余任务是将Neptune连接到宿主机端DirectX渲染器。有三个主要项目可以处理macOS上的DirectX,但它们都主要针对Wine设计,缺乏Neptune和Triton所需的共享纹理和共享围栏功能。

DXVK + MoltenVK:在Linux上效果很好,但在macOS上,Vulkan由另一个转换层MoltenVK处理,不稳定且需要大量兼容性工作。

DXMT:通过将D3D11直接转换为Metal(D3D12即将推出)来绕过Vulkan问题。我们创建了原生变体,使其可作为macOS共享库构建,并暴露了纹理和围栏的导入/导出功能。

D3DMetal:苹果为游戏移植工具包制作的DirectX API实现,包含D3D11和D3D12在Metal上的实现,以及从DXBC/DXIL到AIR的转译器。它不开放源代码,因此我们需要使用swizzling和vtable修补来拦截API调用并更改输出。我们创建了d3dmetal-native包装器,使其能在Wine之外工作并支持这些额外功能。性能显著优于DXMT。

总结

所有工作都是开源的。我们正在积极将这些更改上游化,并很快更新UTM以支持这些功能。

评论总结

根据评论内容,主要观点如下:

1. 对Windows虚拟机3D解决方案的积极评价
- 评论3(作者jamesu):“终于有了一个不错的开源3D解决方案用于Windows虚拟机”("Pretty cool to finally have a decent open 3d solution for windows vms")
- 评论1(作者ramshanker):“没什么可失去的,收获却很多”("Nothing to lose and a lot to gain")

2. 对技术局限性的关注
- 评论5(作者thehias):“为什么总是只有DX11,而不是DX12?Parallels和VMWARE也只能做到DX11?”("why always only DX11, why not DX12? Parallels and VMWARE can also do only DX11??")

3. 项目名称重复的提醒
- 评论4(作者mutkach):“这至少是第三个名为Triton的GPU相关项目”("That’s like (at least) third GPU-related project named Triton")

4. 对其他平台支持的期待
- 评论3(作者jamesu):“如果有人能为旧款Intel MacOS虚拟机制作OpenGL驱动就好了”("Now if only someone made an opengl driver for older intel macosx vms...")

5. 信息补充
- 评论2(作者anonymousiam)提供了Phoronix的详细报道链接。

总结:评论整体对Triton项目表示认可,认为其填补了Windows虚拟机开源3D解决方案的空白,但指出其仅支持DX11的局限性,并提醒项目名称与已有项目重复。部分评论期待未来能支持更多平台和API。