研发实战:如何在Oculus Mobile VR平台进行Vulkan开发
来源:映维网 作者 颜昳华
移动 VR 从一开始就将OpenGL ES作为图形API,但现在大多数引擎都开始转向Vulkan和DX12等API,因为它们为开发者提供了更大的灵活性和更低的渲染负载。Oculus日前介绍了GL和Vulkan在开发VR 游戏 功能方面的差异。需要注意的是,本文深入介绍了与图形相关的细节,读者需要掌握GL和Vulkan的基本知识。下面是映维网的具体整理:
由于Adreno图形驱动和Oculus运行时方面的改动,下面介绍的大多数功能都需要新发布的Build 7.0版本。
1. 多重采样抗锯齿(Multi-sampling Anti-aliasing;MSAA)
与PC显卡不同,移动芯片集的MSAA是由Tiler执行MASS操作,然后当Tile完成时进行解析(将所有子样本平均到最终像素),再将其结果存储到主存储器。由于从Tile内存到一般内存的带宽是非MSAA,这允许我们以接近与非MSAA相同的速度运行MSAA帧缓冲器。这对VR非常重要,因为每个眼睛的像素非常低,会产生明显的边缘锯齿。
对于GLES,这是通过使用MSAA帧缓冲区将其渲染到非MSAA纹理来完成。MSAA帧缓冲区使用以下函数进行初始化:glFramebufferTextureMultisampleMultiviewOVR
尽管有效,但由于其隐式性质,这引起了一系列的问题,例如“我不认为我的系统支持MSAA,我的纹理只是RGBA8888,我如何启用MSAA”。
在Vulkan中,由于一切都为显式。每个子通道由包含pColorAttachments,pDepthStencilAttachment和pResolveAttachments的vkSubpassDescription结构定义。一个优秀的Vulkan应用程序应该通过附着4x MSAA缓冲区来设置MSAA,并将其用于颜色/深度附件中的颜色和深度,以及pResolveAttachment中的非MSAA颜色缓冲区。应用程序同时应该将pColorAttachments和pDepthStencilAttachments storeOperations设置为VK_ATTACHMENT_STORE_OP_DONT_CARE。这将告诉驱动:“我以后不会要求这种颜色或深度,请不要将它们存储在Tile内存中并丢弃它们”。
加分项是,MSAA颜色和深度缓冲区应该设置为瞬态,并且系统会慢吞吞地分配它们的内存,因为所述缓冲区甚至没有内存(唯一的是pResolveAttachment中的颜色解析附件)。下面是一个优秀的管道状态示例:
使用这一路径(通过renderpass/subpass系统进行MSAA处理)而非vkCmdResolveImage路径非常重要。vkCmdResolveImage路径是一个以PC为中心的API,它不会利用Tiler在存储期间解析的能力,所以通过vkCmdResolveImage命令执行MSAA的引擎会将4x MSAA数据存储在内存中,再次从内存加载到Tiler ,然后将非MSAA解析回内存。这很容易就会给GPU添加3ms。
2. 多视图(Multiviw)
每次提交时,Multiview这个扩展允许GPU驱动程序在纹理数组的N个不同的切片(slice)执行N次绘制调用。它在VR中通过单次绘制调用来在2-deep纹理阵列绘制左眼和右眼。Vulkan通过VK_KHR_Multiview扩展提供支持。它需要颜色,深度和解析图像为2D Array而非2D,并且需要将VkRenderPassMultiviewCreateInfo结构添加到要通过Multiview执行的渲染通道。它(在UE4.23进行了测试)支持多个子通道。renderdoc管道状态图片(与上面相同)展示了具有2个视图的多视图捕获(一个用于左眼,一个用于右眼)。
VkRenderPassMultiviewCreateInfo有一个pViewMasks参数,其要求对多视图的视图数进行按位掩码。对于viewMask[0]值为0b11,双视图系统要求bit0和bit1为真。
我们的运行时本身支持纹理数组作为时间扭曲合成的输入纹理。开发者应该使用VRAPI_TEXTURE_TYPE_2D_ARRAY枚举创建纹理,而非渲染到多视图缓冲区,然后再手动将它们复制到非多视图图像并发送到VRAPI(计算要求非常高)。
3. 固定注视点渲染(Fixed Foveated Rendering;FFR)
从开发者的角度来看,由于两个FFR API之间存在较大的架构差异,所以GL和Vulkan之间的FFR非常不同。从概念上讲,FFR是一种应用于帧缓冲区的渲染设置,因为它会修改GPU计算帧的方式,同时不会以任何方式影响纹理(无论发生什么,颜色和深度纹理中的所有纹素都会被填充)。
实际上,来自QCOM的原始FFR扩展应该通过glFramebufferFoveationConfigQCOM函数应用于帧缓冲区,而老实说它应该存在于API中。但对于Oculus Go,我们希望在无需深入的引擎/应用改动的情形下引入这项功能。更重要的是,我们希望运行时控制应用的注视点设置,这样我们就不需要每位开发者和引擎来控制FFR设置,并且整个平台上都会具有同类设置。所以,我们要求QCOM在颜色纹理中存储FFR元数据(由我们控制,因为运行时分配纹理而非帧缓冲区),因此诞生了glTextureFoveationParametersQCOM。从开发者的角度来看,这个实现在很大程度上是隐藏在运行时中。开发者请求FFR级别(关闭/低/中/高),而我们自动为他们配置更低的级别。
尽管这个解决方案为Go和Quest带来了相当大的帮助,但它却面临着多重挑战。首先,因为它是基于VRAPI修改颜色纹理元数据,所以每个预通道(不会渲染到颜色纹理中)都不是根据注视点进行。现在没有太大问题,因为我们的大多数应用程序都是单通道,但情况总是会发生改变,因为开发者希望启用(例如)HDR管道。其次,QCOM有一个硬编码的注视点功能模型,它不允许我们根据视场和透镜来选择我们真正想要的分辨率曲线。
通过引入VK_EXT_fragment_density_map扩展,Vulkan完全修复了这个问题。需要注视点渲染的应用程序渲染通道不是采用硬编码方程式,而是添加另一个图像附件。它不是写入附件,而是读取附件。这个附件是一个R8G8像素密度图像,与普通附件相比(1216×1344渲染通道将具有38×42片段密度附件),其分辨率为/32并驱动应该渲染的帧缓冲区域的分辨率。
下面是一个片段密度图像示例。黄色区域是我们1:1的高分辨率区域,离屏幕中心越来越远,像素密度将越来越小。
尽管上图纹理有一种注视点的形状,但这种纹理可以是你想要的形状。例如,如果开放世界游戏的开发者不太愿意花费太多时间,他们完全可以减少天空的有效分辨率。对于以方程式为中心的GL扩展,这是完全不可能的事情。纹理同时可以绑定到任何渲染通道,所以双通道HDR-LDR渲染器的开发者可以简单地绑定两个渲染通道中的纹理,并将FFR应用于两者。
考虑到我们还是希望维持VrDriver对注视点曲线的控制,但rendepass是完全由应用程序控制,所以我们最终采用了混合方法。当开发者创建交换链来从Vulkan中的Oculus运行时获取颜色纹理时,它会创建另一个交换链:注视点交换链,其中颜色交换链的索引0与注视点交换链的索引0匹配,依此类推。开发者可以通过新的vrapi_GetTextureSwapChainBufferFoveationVulkan函数请求注视点交换链图像,并且无需对其进行任何修改,只需将它们绑定到自己想要启用FFR的渲染通道即可。
当使用普通的FFR控制API时,我们的运行时将修改注视点交换链图像并生成一个注视点图像,其强度与开发者请求的设置相对应。上图示例是运行时为High注视点设置生成的注视点图像。如果引擎没有任何进一步的变化,图像将自动切换注视点曲线,下一个renderpass的执行将使用新的FFR设置,就像开发者使用OpenGLES的FFR扩展一样。
4. 工具
Vulkan的一大优势是它是PC和Mobile共享的图形API。最重要的是,它是一个无状态API,这意味着驱动程序不需要在命令之间存储基础状态。这极大地帮助了像RenderDoc这样的工具。它支持MSAA,Multiview,VK_EXT_fragment_density_map,并且自RenderDoc 1.4起就可以配合Oculus Quest一起使用。片段密度贴图纹理可以在RenderDoc中可视化,从而确保你获得自己想要的注视点图像,并且帧将包含注视点图像,所以你可以看到头显中的真实纹理输出。
5. 引擎
Oculus 4.22.2 release 1.39.0是我们建议用于Vulkan开发的首个UE4版本。它实现了MSAA,Multiviw,FFR,sRGB原生渲染和多个UE4-Vulkan漏洞修复。注意,要在GitHub中访问所述文件,你需要登录订阅账号,否则你将会看到404错误页面。
我们看到了相当不错的性能增益,一个SunTemple的开发版本在渲染线程上从16ms变成了13sm。另外,由于着色器是SPIRV预编译而非GLSL,加载速度有了显著的提升。
不仅只是速度,Vulkan优化的设计和固有的多线程处理允许我们实现GLES所无法支持的功能,如引擎内每帧定时器查询。stat unit中的GPU定时器数据现在已经可用,并由引擎生成的计时器查询驱动,不再是从运行时传回的平均数据,而且stat gpu为你提供逐渲染通道信息。Vulkan同时允许我们能够开始考虑未来的理论功能,如基于子通道的HDR,多线程着色器加载,简单的色调映射等等。
尽管我们发现这一版本和最新的Quest操作系统就Vulkan而言相当稳定,但对UE4-Vulkan-VR来说仍然是早期阶段,所以如果你遇到任何问题,请向我们报告反馈。
6. 示例
Oculus Mobile样本目录中的VrCubeWorld_Vulkan样本现在已经实现了所有这些功能,你可以进行参阅并从中获取灵感。
7. 总结
希望这篇文章能够为你当前的Vulkan图形开发工作带来帮助,或者如果你是原生开发者或UE4开发者,希望这篇文章可以鼓励你尝试使用Vulkan。除了允许你在PC和移动平台之间轻松共享代码之外,它同时可以令你的图形代码工作更清晰,更快速。
原文链接:https://yivian.com/news/64773.html