上海:2025年国有企业在数字经济中的比重将翻一番
06-18
加入英伟网会员文章相关引用和参考文献:gpuopen本文来自Croteam的引擎程序员 Karlo Jez,目前负责《Serious Sam VR: The Last Hope》。
(2020年11月24日)AMD的MultiView渲染功能可以减少VR应用中复制对象绘制调用的次数,允许GPU在一次绘制调用中将对象广播到左眼和右眼(原本渲染两个二流)。
这有助于减少 CPU 负载,从而减少丢帧并优化渲染延迟。
当我们开始使用单通道渲染时,我们首先使用多个 GPU,因为它更容易实现并且对性能影响最大。
不幸的是,尽管 GPU 在 VR 渲染中发挥着巨大作用,但我们大多数用户都无法使用多个 GPU。
因此,我们计划在单GPU上支持MultiView渲染。
MultiView渲染并不会真正影响GPU负载,但可以显着降低CPU的渲染负载。

对我们来说,支持同一组着色器并确保所有支持的 VR 渲染方法尽可能高效非常重要,从而最大限度地减少仅出现在其中一种渲染方法上的错误数量。
使用 LiquidVR Affinity Multi-GPU,双眼图像会渲染到同一渲染目标的同一视口,但一个位于主 GPU 上,另一个位于另一个 GPU 上。
渲染后,图像被复制到主GPU上的不同渲染目标,并传递到VR系统进行显示。
在单 GPU 渲染的情况下,两个图像不能同时存在于 2D 渲染目标的同一视口中,但我们可以使用渲染目标数组或包含两个并排视图的渲染目标。
我们决定使用并行渲染,因为我们想避免编译一组单独的着色器(我们在Future Rendering中没有使用Texture2D,而是使用Texture2DArray),并且因为我们想通过Future 尝试未来的MultiRes Rendering 实现。
对于单个 Radeon GPU 上的 Kongfung 渲染,我们使用了 AMD GPU 服务 (AGS) 库。
除了一些初始化函数之外,我们只需要库中的一个函数:agsDriverExtensionsDX11_SetViewBroadcastMasks()。
要在同一渲染目标上使用两个视口启用MultiView渲染,我们调用: agsDriverExtensionsDX11_SetViewBroadcastMasks(context, 0x3, 0x1, 0);第二个和第三个参数是最重要的,因为它们将选择视口和渲染目标切片蒙版。
渲染时,我们不设置单个视口,我们同时设置两个视口: D3D11_VIEWPORT ad3dViewports[] = { {fLeftX, fY, fHalfWidth, fHeight, fNear, fFar}, {fRightX, fY, fHalfWidth, fHeight, fNear , fFar} };pd3d11context- RSSetViewports(2, aViewports);对于基于 Affinity Multi-GPU 的单通道渲染,我们仅使用每个 GPU 不同的常量缓冲区;所有其他数据都相同,即两个 GPU 都有双眼的渲染数据,但只选择其中一个进行渲染。
这使得在单个GPU上添加对MultiView渲染的支持变得更容易。
因为所有数据都在同一个 GPU 上,所以同一个常量缓冲区中不能有不同的值。
要通过 AGS 获取每只眼睛的正确矩阵,唯一需要的更改是使用 AmdDxExtShaderIntrinsics_GetViewportIndex()。
我们没有选择 GPU 索引,而是在 Affinity Multi-GPU 模式下将命令缓冲区传递给两个 GPU。
uint GetVREye() { // c_multiview 是传递给所有着色器的常量 return (c_multiview 0.0f) ? AmdDxExtShaderIntrinsics_GetViewportIndex() : c_eye;当启用Future时,该函数返回视口索引;当MultiView被禁用时,该函数返回眼睛常数。
在多通道渲染中为每个渲染通道设置眼常量,或者在 Affinity Multi-GPU 模式下渲染单通道时将眼常量上传到每个 GPU。
该索引可用于获取所有着色器上每只眼睛的数据,无论使用何种渲染方法。
在MultiView模式中,我们使用两倍于通常宽度的渲染目标。
从外部代码(即更高级别)的角度来看,渲染目标是原始大小(一半),例如× 渲染目标将在内部创建为 × ,但是当从外部代码查询纹理尺寸时,您将得到 × 。
这样做的目的是尽量减少MultiView需要感知的代码量。
只有着色器和底层渲染函数需要知道实际纹理大小或我们正在使用MultiView渲染的事实。
当绘制到渲染目标时,一切就像分两次渲染场景一样,每次都使用不同的视口。
如果我们想要采样MultiView纹理,我们需要在渲染左眼视图时采样纹理的左半部分;我们在渲染右眼视图时需要对右半部分进行采样。
为此,我们使用 MAD 来调整 UV 坐标。
因此,对于左眼,它们不是从 (0.0, 0.0) 到 (1.0, 1.0),而是从 (0.0, 0.0) 到 (0.5, 1.0);右眼从 (0.5,0.0) 到 (1.0,1.0)。
我们如何为每只眼睛提供不同的值?答案是AmdDxExtShaderIntrinsics_GetViewportIndex()。
float4 GetMultiviewMAD() { uint eyeIndex = AmdDxExtShaderIntrinsics_GetViewportIndex();返回 float4(0.5f, 1.0f, 0.5f * eyeIndex, 0.0f);为了能够在 MultiView 和非 MultiView 渲染中使用相同的着色器代码,我们添加了所有需要在采样之前应用 MAD 的着色器,但我们向该函数添加了一个条件,因此当 MultiView 被禁用时,它将返回 (1.0, 1.0、0.0、0.0)。
添加MultiView支持最具挑战性的部分是检查所有着色器并将 MAD 应用到正确的位置。
这些主要是后处理着色器,因为它们经常对先前渲染的纹理进行采样。
当我们错过一些视觉伪像时,通常很难不注意到它们。
这些着色器渲染的图像大小是两倍,并且它们的长宽比不正确(因为您将对整个图像进行采样,而不是一半): 这是正确渲染的场景(仅左眼视图): 这是相同的场景,但是其中一个后处理着色器(FXAA)缺少MultiViewMAD:我们可以注意到图像是如何被挤压的,并且左眼可以看到右眼视图的一部分。
我们可以通过在采样纹理之前调整UV坐标来解决这个问题。
修复了所有渲染错误后,我们可以看看 SteamVR 游戏中的帧计时。
禁用 MultiView渲染: 启用 MultiView渲染: 可以看到两种情况下 GPU 帧时间几乎相同(约 6.5 毫秒),但 CPU 从 9 秒减少到 7 毫秒,这与我们得到的结果相同LiquidVR Affinity Multi-GPU 结果类似。
在这种情况下,性能提升不到两倍,因为我们的 VR 渲染器已经进行了相当程度的优化,但主渲染通道只能通过 AGS 每帧执行一次,因此我们不需要花费 2 毫秒来处理渲染命令,但 4 毫秒。
结论 在已经支持 LiquidVR Affinity Multi-GPU 的引擎中添加对 Kongfun 渲染的支持并不困难,因为我们提前计划了。
在开始添加MultiView支持之前,我们将所有着色器设置为单通道渲染。
相反,一开始就增加对MultiView的支持存在一个更大的初始障碍,因为我们需要处理单遍错误和MultiView错误。
但一旦完成,我们就可以非常轻松地添加 LiquidVR Affinity 多 GPU 支持。
补充低级功能非常重要,这些功能为MultiView提供清除或复制视口的意识。
如果视口的一部分被清除,右眼也必须做同样的事情。
视口复制需要考虑是否从MultiView纹理复制/复制到MultiView纹理,并进行相应操作。
另一件需要考虑的事情是使用 SV_Position 语义读取像素着色器输入。
我们需要小心,因为它给出了渲染目标的像素中心相对于渲染目标(而不是相对于视口)的坐标,因此右眼视图的值将成为纹理右半部分的坐标。
这并不是MultiView渲染所特有的,而是我们对返回值范围的错误假设导致了一些渲染错误。
版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
标签:
相关文章
06-08
06-17
06-18
最新文章
英国肖像画家用Tilt Brush探索VR雕塑
微软75亿美元联姻B Corp母公司,以3件VR大作作为嫁妆
传闻苹果AR-VR眼镜原型机将于下个月发布,量产推迟至2022年初
调查显示,大多数游戏玩家对虚拟现实不感兴趣
一睹购物未来,亚马逊VR购物在印度试水,带你畅游虚拟商务中心
这是Nvidia是这么解释什么是AR、VR、MR的,以及对应的区别
iPhone12 Pro完成了谷歌的使命,为苹果的AR眼镜铺平了道路
研发实践:在VR游戏中添加LiquidVRMultiView渲染