高质量的游戏体验离不开高画质和高性能,由于手机硬件条件的限制,如何合理平衡各项参数成为了重中之重。三星Galaxy GameDev组负责与全球的游戏研发者一起专注于研发高画质、高性能的游戏,并研发了两个优化技术Adaptive PerformanceVulkan

Unity线上技术大会中,来自三星电子(中国)研发中心的姚巍和陆星宇共同为大家带来了详细的功能解读及案例分享(包括《使命召唤》手游、《百魂战记》等),该演讲已上传至Unity B站,您可以点击“阅读原文”跳转观看。

以下是演讲全文。

打开网易新闻 查看更多图片

姚巍

三星电子(中国)研发中心首席工程师

姚巍是三星电子(中国)研发中心的首席工程师,曾参与《王者荣耀》《PUBG》《天涯明月刀》《尼尔机械纪元手游》《Traha》《Gran Saga》等国内外游戏Vulkan优化和开发。

打开网易新闻 查看更多图片

陆星宇

三星电子(中国)研发中心工程师

陆星宇是三星电子(中国)研发中心的工程师,曾参与《PUBG》《崩坏三》《尼尔机械纪元手游》《英雄联盟手游》等国内外游戏Vulkan和adp方案的优化和开发。

Galaxy GameDev组

首先我来介绍一下Galaxy GameDev组,该组成立于2016年5月25号,可以看到我们的组分布在全球的各个地方,所有的组并不是仅负责当地的具体业务,而是会与全球其他的组协同工作,互相支援。

打开网易新闻 查看更多图片

这里展示了一些我们的合作伙伴,可以看到从国内到国外独立的游戏工作室、游戏巨头都与我们合作过。

打开网易新闻 查看更多图片

全球的开发者对手机上的优化有各种各样的需求,我们总结了所有的需求以及问题,将游戏的优化、支持分成了四大块。这四大块当中,除了底层的设备驱动之外,我们还负责为开发者提供了一些工具和SDK,比如三星手机上专有的GPUWatch,可以让你的手机在不连接任何外设的情况下,可以看到游戏的具体渲染情况。

打开网易新闻 查看更多图片

当然除了这个,我们也会为开发者提供更直接的支持,包括线上的交流以及线下的驻场服务。驻场的主要内容,就是帮助开发者更好地运用今天所提到的这两个优化技术,一个是Adaptive Performance,还有一个是Vulkan。

Adaptive Performance

Adaptive Performance是我们与Unity合作,基于GameSDK开发的功能。首先介绍一下它的诞生背景。

在移动平台上,特别是在负载较高的游戏过程中,由于主动的冷却系统的缺失、以及电池带来的电量限制导致的发热和能耗,成为了手机性能的重要瓶颈。目前在手机平台唯一的办法,就是降低CPU和GPU的频率,以此来降低功耗。但是这样就会导致游戏的性能直线下降,对游戏体验极为不利。

打开网易新闻 查看更多图片

我们把这种情况叫做温控调频(Thermal Throttling),目前的手游开发者是没有办法去干预这种情况的。

为了解决这个问题,我们与Unity合作,基于Galaxy GameSDK推出了引擎Adaptive Performance的优化方案。通过GameSDK将温控相关信息提供给了开发者,方便他们为自己的游戏定制最优化的性能方案

首先我们先来看一下正常情况下温控调频发生的过程,图中可以看到以60FPS的帧率开始,由于能源和散热的限制,在温度上涨到一定程度(也就是图中Throttling出现的地方),手机一般会采取相应的降频措施,其结果就是FPS受到了极大的影响,变得非常不稳定,可以看到最后FPS的数值是40。

打开网易新闻 查看更多图片

为了解决这个问题,GameSDK首先给开发者提供了一个温控信息,即温度告警信息。我们将温度警告信息划分为三个等级,并且通过onHigh TempWarning这个函数回调,0表示当前温度还比较低,不需要调整;1则表示目前需要做一些调整,不然温度就要撞到温控墙了;2就表示时间已经晚了,我们已经进入了温控墙的领域,并且温控墙的策略已经受到了调用。

打开网易新闻 查看更多图片

除了告警信息以外,GameSDK也为开发者提供了很多其他的温度信息,包括内部的温度信息、CPU和GPU的温度以及手机的表面温度。这些温度也被抽象为不同的等级,如果当前温度等级持续升高的话,我们就要考虑做出相应的调整。

打开网易新闻 查看更多图片

当然,移动平台上只考虑温度是不够的。刚才也提到手机的电量是有限的,有的时候,维持帧率的频率过高,远高出游戏的需要,而有的时候,维持的频率过低导致游戏性能下降,这其中的平衡点需要我们用动态的CPU和GPU的frequency调整来实现。

ADP在GameSDK的帮助下,可以通过判断瓶颈来实现动态频率调整,以达到节省电量的目的。GameSDK通过setLevelWithScene API,帮助开发者调整CPU和GPU的运行频率。同样的,这些频率也被抽象成不同的等级,从0开始直到设备支持的最高频率等级。

打开网易新闻 查看更多图片

接下来让我们看一看调整频率的策略是怎样的。

如下面的帧率图所示,当实时帧率达不到target FPS的时候,我们就需要去调整CPU和GPU的频率。如果是CPU的瓶颈,我们就需要调整CPU的频率,把CPU的频率升高。如果是GPU的频率有瓶颈,我们就调整GPU的频率。

打开网易新闻 查看更多图片

但是问题来了,我们怎么知道频率发生的CPU还是GPU呢?这就牵扯到了一个Bottleneck Identify的问题。

这里我们可以使用getGpuFraeTime接口,获取GPU的运行时间。通过对GPU的FrameTime和整体的FrameTime进行一个比较,我们可以确定当前的性能瓶颈是在CPU还是在GPU。如图所示,GpuFrameTime超过了整个画面FrameTime的时间,因此我们可以判定 GPU发生了瓶颈,我们需要提升GPU的Level。

打开网易新闻 查看更多图片

总结来讲,GameSDK提供了很多和设备相关的信息,包括了温度趋势、发热状况、CPU/GPU频率以及用来判断瓶颈的FrameTime的信息。上面这些接口,目前封装在了Unity Adaptive Performance开发包中。我们使用开发包中所提供的接口,即可方便地获取设备的温控和功耗信息。

除了上面的这些硬件信息外,在正常的APP开发中通常会加入一些可以实时调整的话题参数,具体原因我们之后会讲到。

实际上,Adaptive Performance就是利用这些从GameSDK得到的设备信息,以及从引擎上获取的画质参数,去帮助开发者平衡他们的游戏画质和性能。

打开网易新闻 查看更多图片

接下来,我们就从三个游戏案例中看一下Adaptive Performance是如何进行具体工作的,包含《使命召唤》手游版、《百魂战记》以及《全民打棒球》。我想着重介绍一下《使命召唤》手游版的实现细节。

我们先来看看ADP在《使命召唤》手游中的应用表现。

首先我们通过大量的测试,总结出了最适合用来动态调整四个话题参数,在能耗调整、温度趋势和温度控屏警告信息的帮助下,话题参数会得到相应的调整。目前我们罗列的话题参数,包括Shadow Distance、Foliage LoD、Animation LoD、Target Frame Rate。另外Power Management的策略,也在有效进行中,可以在瓶颈检测的帮助下,帮助我们去提升相应的CPU和GPU的Level,让效果最大化。

打开网易新闻 查看更多图片

我们详细地分析一下这些Scaling Factor对画质和对系统负载的影响。

首先我们想回答一个之前留下来的悬念,为什么我们需要Scaling Factor?很多时候CPU、GPU即使是在最高的等级,也没有办法实现流畅的高画质。温度进入温控区间,温控调频的时间将大大提前,在本地中就是这样的情况,所以我们需要降低部分画质参数来降低游戏的负载。可以看到Shadow Distance能带来最高10%的CPU负载降低,而Foliage LOD会带来5%的 GPU的负载降低,其他的两个是同时利好CPU和GPU的。

打开网易新闻 查看更多图片

从画面表现上来看,前两个参数对画面的影响比较大,大家可以从这两幅动图里面看到这两个参数的实际影响。Shadow Distance决定了我们渲染阴影的距离范围,而Foliage LOD可以影响草皮的精细度。但是这些参数在实时游戏的过程中常常被忽略,因为画面是动态调整的,而且每次的调整都是比较细微的。

打开网易新闻 查看更多图片

Shadow Distance (80 ~ 50)

打开网易新闻 查看更多图片

Foliage LOD (1.0 ~ 0.8)

虽然这些参数的调整并不能带来非常显著的性能提升,但是在温控调频发生之前进行调整,可以有效减慢进入温控调频区间的时间

我们来看看ADP与正常情况的系统数据对比,大家可以看到数据对比的结果是非常显著的。通过ADP,我们收获了更高的FPS和帧率的稳定性,平均帧率从54提高到了58,提升高达7%

打开网易新闻 查看更多图片

ADP是如何实现这种提升的呢?接下来我们观察一下温度和能耗的数据。

通过温度图,我们可以看到ADP使游戏过程的温度平均降低了两度,最高降低了三度。而通过频率图,我们可以看到CPU的频率降低了,而GPU的频率则维持在一定的水平,这说明CPU是不需要用那么高的频率去维持当前的帧数。

而在无ADP的情况下,CPU的频率实际上是维持在高位的,这导致性能浪费,反而让我们更快地进入温度控制区间,从而导致了GPU的频率持续降低。在ADP调频策略的帮助下,可以避免CPU的性能浪费。根据上面的结果,我们可以得出结论,ADP为《使命召唤》手游带来了巨大的竞争优势

打开网易新闻 查看更多图片

接下来两个例子我会比较简略地说明。

首先是《百魂战记》,这是一款即将上市的游戏,同时它未来也会在国服上市。可以看到它的FPS提升了三帧,并且FPS稳定性也有很大的提升。

打开网易新闻 查看更多图片
打开网易新闻 查看更多图片

温度和频率数据告诉我们,它还达到了很好的减缓发热的效果。CPU的频率低于普通情况下的频率,说明调频的策略是有效的。

打开网易新闻 查看更多图片

《全民打棒球》已经上市,你可以看到CPU频率的调整是非常有效的,带来了不错的性能优势。

打开网易新闻 查看更多图片
打开网易新闻 查看更多图片
打开网易新闻 查看更多图片

接下来我将为大家介绍一下Adaptive Performance 2.0,可能有人会问1.0和2.0的区别在哪?1.0版本中我们更加注重Power Management,也就是能耗管理,通过降低CPU和GPU的过度使用,来降低能耗。在画质管理方面,我们需要开发者主动提供相应的接口。

Adaptive Performance 2.0版本得益于我们跟Unity在引擎端的合作,画质参数这方面的空白得到了极大的补充和完善。在1.0中,游戏开发者需要自己开发可调整的画质参数,而2.0提供了非常多的原生参数结果。除此之外,2.0还提供了非常方便的调试功能。首先开发者可以在Editor自带的调试器里面观察到这些画质参数调整对游戏画面表现的影响,其次,通过ADP的UI的界面,开发者可以非常方便地选择将哪些画质参数纳入到这个ADP的调整范围。

最后我们还提供了一些非常方便的测试用例,这些测试用例的侧重点各不相同。我们会在之后介绍。

另外,由于最新的三星手机支持多种屏幕刷新率,所以调整屏幕刷新率的Automatic VRR也被加入到了ADP之中。ADP 2.0最低支持2019 LTS及以上的Unity版本,正式支持的版本是2020.2。对于ADP 1.0来讲,如果想要启用Automatic VRR功能,需要至少2018.3的Unity引擎版本。

接下来,我们将会用《Boat Attack》这个例子阐明2.0的新特性,该用例采用了Universal渲染管线,并且集成了ADP 2.0。

打开网易新闻 查看更多图片

在这里,大家可以看到ADP 2.0的测试数据。测试的持续时间大概是10分钟,这个Demo会消耗比较多的GPU资源,大家可以看到数据最高达到了92%,所以温度上升地非常快。在5分钟以后,也就是红框显示的范围,在没有ADP的情况下,FPS出现了大幅下降

打开网易新闻 查看更多图片

和1.0一样,在手机达到高温的时候,温控调频的策略将会被调用,从而影响性能表现。根据上面展示的FPS图来看,在5分钟以后,Normal case FPS就迅速下降了。现在我们可以仔细观察一下这张平面图红圈的部分,这里ADP 2.0的行为其实和1.0没有什么太大的区别,它会尽量压低CPU和GPU的频率,并且同时保持性能。不同的是,2.0可以提供非常多的新参数。

打开网易新闻 查看更多图片

现在GIF里面的就是ADP和Normal的画面对比。

打开网易新闻 查看更多图片

上面是ADP,下面是Normal

通过上面ADP的例子,大家可以观察到这个ADP是如何动态调整参数的。这些白色的字段包含了这些参数的实时数据,以及可以调整的范围。可以看到,参数调整带来了GPU LOD和FPS的改变,其结果是这些参数调整有效降低了GPU的负载。由于该Demo中存在大量的GPU占用,其实只减少一点GPU负载也可以带来非常明显的性能提升。虽然动态调整参数会带来一些画面表现的变化,但是就我对这两个视频对比的观察,很难看出画质的区别,反而在ADP的情况下更加流畅稳定。大多数情况下,这些参数的变化在移动端不会非常的明显。

目前ADP 2.0支持图中的可调参数,在右侧的图里面,大家可以看到各个参数的调整范围和当前的数值。和1.0不同的是,开发者不需要自己动手写脚本,ADP已经完成对这些参数的封装。然而开发者依旧需要对这些参数进行详细的测试,因为不同的游戏有着不同的系统瓶颈,而不同的参数又会导致CPU和GPU不同,所以我们需要特定的解决方案,所幸前面介绍的模拟器的支持和UI界面的支持,可以简化这个过程。

打开网易新闻 查看更多图片

由于时间关系,我就不一一介绍这些indexer了。如果你担心这些参数的调整会对画面表现造成比较大的影响的话,可以先在模拟器里面实验一下。根据我们组的经验,除了分辨率和目标帧率以外,其他参数的降低都能做到比较好的平衡,降低负载的同时保持比较好的画面质量。

这里我们准备了一组GIF,来展示这些参数带来的画面表现的影响。

这幅图展示了LOD scaler的影响,如果你仔细观察那些棕榈树的话,也许可以看出一些区别。

打开网易新闻 查看更多图片

Texture Quality Scaler的影响,主要体现在石壁的表面,但是同样比较难以察觉。

打开网易新闻 查看更多图片

这张图展示了Render Scale Scaler的影响,就我个人而言,我很难观察到参数带来的区别,所以我决定用RenderDoc去做一个截帧的分析。

打开网易新闻 查看更多图片

同样的场景,我就Render Scale参数为0和2的情况,分别得到了如图所示的结果。

打开网易新闻 查看更多图片

这些我们可以看到同样的纹理,其分辨率从512×512降低到了256×256,这无疑是有效减少了带宽,而手机上最缺少的资源就是带宽资源。通过选择合适的参数,并且制定相应的调整策略,开发者可以平衡画面表现和性能表现,从而牺牲少量的画面表现,就可以获得较大的性能提升。

打开网易新闻 查看更多图片

这里我们介绍一下Automatic VRR的特性,为了适配新款三星手机的刷新功能,ADP同样提供了可以改变数据的接口。有时候我们并不需要那么高的刷新率,同时维持这样的高刷新率是非常耗能的,比如说左边的暂停状态。通过ADP的接口,我们可以根据场景的不同动态调整刷新率,来达到降低能耗的效果。

打开网易新闻 查看更多图片

ADP中的几个模块,温度告警、瓶颈检查、性能调整以及帧率的调整,都有相应的例子可以进行测试。这些测试用例,你都可以在Unity官网上面找到,他们各有特点,可以帮助你去更好地触发逻辑,检查你的逻辑是否正常有效。

到此,ADP 2.0的改动以及ADP的工作原理和机制的讲解就结束了。总而言之,通过GameSDK提供的各种温度信息以及CPU和GPU的信息,ADP可以调整出最高效的硬件频率水准。同时通过动态改变游戏画质参数,ADP可以有效降低游戏的负载,从而达到延缓升温的目的。我们相信,这些优化将会为用户提供更好的游戏体验。

关于ADPP就先介绍到这里,接下来将由我的同事姚巍,来介绍Vulkan优化的相关内容。

Vulkan

接下来就由我向大家介绍一下,我们在Unity引擎上所发现的几个最主要的Vulkan优化点。

首先,我跟大家介绍一下Vulkan API的一些特点,并且重点从两个部分介绍优化工作,一个是DescriptorSet,另外一个是Vulkan里面的Renderpass。

关于Vulkan,其实网上有很多的资料,它最大的不同在于相比GLES,Vulkan不再是状态驱动,而是会将这些管线的状态去分布在对应的Vulkan对象当中去。这个就表明我们可以更方便地去追踪GPU资源在渲染过程中状态的动态变化,同样也为我们复用这些对象提供了可能。

打开网易新闻 查看更多图片

同时,Vulkan更适合多线程,为什么呢?因为它没有全局的context,在这种情况下,它能更好地在多线程当中去实时修改对应的状态。同时,因为它没有完整的管线状态,所以它可以在这些对象中动态地修改复用。

接下来,我们会介绍DescriptorSet优化,其中会有非常多的缓存应用,它的核心思想就是缓存DescriptorSet的对象。

首先我们来看一下第一个方案,关于Use Ring Buffer Forniform Data,我们该如何去存储?我推荐使用一个大的Ring Buffer去存储,因为有可能每一帧都要向Set去传新的Uniform数据。

在这个图中的案例中,所显示的就是第42帧正在试图向Ring Buffer当中填充一些Uniform数据,而这些数据是GPU马上就要使用到的。我们可以看到这个时候,其实第40帧和第41帧的数据仍然在GPU当中被使用,也就是说我们这块Buffer前面的部分还没有办法释放。我们可以发现,第39帧数据已经完成使用了(我们可以通过Vulkan的Fence去检查是否已完成,显示signal的时候,就可以表明当前帧在GPU当中已经完成),也就表明对应的数据资源其实是可以被释放掉的。

在这个时候,我们看到第39帧Fence在Signal的情况下,我们就释放出了一个空间给第42帧的Uniform数据去使用,所以我们就可以把这些数据填充在空白的地方。大家可以看到这个时候我们的Ring Buffer已经到头了。

打开网易新闻 查看更多图片

还有一种情况,就是Ring Buffer本身就没有办法承载这些数据,或者说39帧空出的这些数据空间,它也没有办法容纳第42帧需要的所有数据时,我们就只能去申请更大的Buffer。

但通常在实践当中,我们建议根据每个游戏的特点,在一开始初始化的时候,就把大的Ring Buffer申请好,避免在运行的过程中去动态销毁/申请内存,这样会造成CPU行程下降。

在有了UniformRing Buffer的情况下,我们还需要了解一个DescriptorSet的重要概念,DescriptorSet Cache,它代表了Vulkan优化中的一个重要特性——对象缓存。

在Vulkan当中,DescriptorSet是一个对象,这个对象是用来描述我们要把什么样的资源传到Shader的。但是在传过去之后,更新DescriptorSet是一个非常重量级的操作。如图所示,我每一个DrawCall进来的时候都会为它更新DescriptorSet,这个更新的操作在移动端是一个非常重要的操作,会直接影响性能。

打开网易新闻 查看更多图片

这个时候,我们就需要用到DescriptorSet Cache,DescriptorSet Cache主要是用于复用DescriptorSet,由于复用过程中不需要重复更新DescriptorSet,所以我们就可以有效地在运行的时候降低它的更新频率。

打开网易新闻 查看更多图片

需要注意的是,我们在存DescriptorSet的时候,会不可避免地存一些资源,比如图片或者Buffer。因为在Uniform资源当中,大部分是texture,还有Buffer数据。

这里面有一个坑,就是存这些数据的时候,千万不能用VKhandler作为它的Key。根据Vulkan的标准,不同的类型对象可能会去共享同一个handler,这些handle同样的值对应不同的对象。而且还有更重要的一点,在你的一个对象被删除的时候,如果再被重新创建,有可能会共享新的handler值。也就是说,如果你用handle去作为Key,很有可能就会造成你引用了错误类型的对象,或者说引用到一些已经被删除的对象,进而会给你的程序带来一些问题。

为了解决这个问题,你可以使用自己记录的一个全局ID值(通过全局只增不减的ID值),去标识唯一的DescriptorSet里面用到的Uniform资源。

可以看到,在你使用DescriptorSet之后,每一次调用只会在我们需要新创建一些DescriptorSet的情况下,才会进行更新操作。如此一来,我们就可以避免为每一个DrawCall去进行这些更新操作。

接下来还有一个重要的概念,就是使用动态的Uniform Buffer。在Vulkan里面它有两种Uniform Buffer的类型,一种是我们通常用的普通类型,还有一种Dynamic类型,就是动态维持。

普通类型的Uniform Buffer有一个问题,就是在面对不同的Buffer偏移的时候,就必须要生成新的。前面我们提到Uniform Buffer的数据是存在一个大的Ring Buffer里面的,在这个里面,我们每个DrawCall所需要的资源,即Buffer的资源,它的Buffer是同样的,但它的偏移值不一样,因为可能数据存在大Buffer当中不同的部分,所以这个部分也需要用offset值去标记。

对于普通Uniform Buffer而言,你的offset不同,它就会需要新的DescriptorSet。像刚刚提到的,如果你需要新的DescriptorSet,就意味着你需要缓存的对象会变多,内存会增长。同样,你新的DescriptorSet进来的时候会需要更新操作,意味着你的更新操作会变多。

打开网易新闻 查看更多图片

这里我们推荐的一种解决方式就是使用Dynamic的Uniform Buffer,因为Dynamic允许相同的DescriptorSet,同时传入不同的Dynamic offset值,这是Vulkan里面的一个核心。我们绑定的时候把offset传进去,这样就可以做到一个DescriptorSet允许多个DrawCall使用。

但是在高通的某些驱动上,有可能会听到这样的声音,即使用Dynamic的Uniform Buffer性能可能会下降。但是综合考虑,使用Dynamic offset还是可以掩盖这些性能弊端的。

接下来我们讲今天Vulkan优化中的第二个重要部分,就是Renderpass的优化。

对于Renderpass,首先我们需要关注Load和Store的操作,Load和Store的操作是Renderpass里面针对attachment进行的。

可以看到这些参数里面,DONT_CARE肯定是最优化的,因为它可以允许GPU跳过一些必要的操作。

打开网易新闻 查看更多图片

这里我们可以简单看一下性能对比,在我们将这些的Renderpass的Load和Store的操作设置成DONT_CARE之后,实际上GPU的工作数量是有一个大幅度减少的,即GPU的利用率会大幅度下降。

打开网易新闻 查看更多图片

当然使用DONT_CARE的时候,我们也必须要小心,不能让它引入一些错误。

我们首先从两点来确定需求是怎么样的。一个是我们当前attachment,是不是不需要前面Renderpass所渲染的结果就可以使用?还有一个是当前是不是全屏渲染?这个很重要。就是说经常我们使用DONT_CARE的时候,虽然我们在前面刷了一个背景,但有可能这个背景会被GPU丢弃掉。如果你当前的帧不是全屏渲染的话,就有可能造成一些花屏的错误。

对于Vulkan里面的Renderpass,另外一个重要的概念是Subpass,在这里我们推荐尽量使用多个Subpass。Subpass的原理是,将一个完整Renderpass所需要做的工作分成各个阶段去完成,每个阶段就对应一个Subpass。

打开网易新闻 查看更多图片

Subpass的好处是,在正常情况下,我们实际上没有办法访问segment set里面渲染的结果,因为GPU对于attachment的保护有特殊的优化。但如果说同时需要去兼顾你的读写操作,就导致它产生多余的同步,然后它就会破坏前面的优化。

当然,在现在的GPU渲染技术里面,有很多Shading的时候,其实需要去依赖于之前的渲染结果,最典型的就是延迟渲染(Deferred Shading)。所以说在这个情况下,通常来说随后要进行的这些渲染操作,和前面的渲染操作会具有相同的分辨率,而且会依赖于前面对于attachment操作之后的渲染结果。

在移动端中,我们知道GPU大部分是Tedpass。Tedpass的GPU其实可以很方便高效地在芯片端去存储attachment的中间结果,所以说它理论上可以给我们提供非常高效的优化方案。这种优化方案下,Vulkan就可以使用Subpass去完成。因为在Vulkan当中,这些Subpass在同一个context里面,可以去贡献这里面的块信息,还有它的分辨率。这也意味着我们后面的Subpass,可以很方便地访问到前面Subpass的渲染结果,而这些渲染结果发生在Renderpass中间。

这里我们就展示了Subpass所具有的三个主要功能,可以看到都是对Input Attachment,即GPU中间的渲染结果,需要读写的时候所具有的一些功能。通过使用这些功能,我们有时候会对程序优化产生一些奇效。具体从两个案例来看一下。

打开网易新闻 查看更多图片

第一个是刚才所提到的Subpass,对于延迟渲染的优化。可以看到在传统的方案当中,我们起码需要两个Renderpass去完成延迟渲染,第一个Renderpass会负责向GBuffer当中写入数据,第二个Renderpass去使用前面写入的数据,texture去载入到Shading当中,然后在Shading当中再重新采样,去做Shading操作、计算光噪之类的,最后生成图像。

如果你使用两个Subpass的话,就可以把原来需要两个Renderpass做的工作合并到一个里面去。这个Renderpass就有两个Subpass,第一个Subpass跟前面一样,负责往GBuffer里面写数据。但是这个时候,我们用的是Input Attachment,因为我们有两个Renderpass,所以这些数据实际上是临时被写在Input Attachment里面的。这些Input Attachment,就正好存在Tile Base内存当中。之后的第二个Subpass,它就不需要多余的载入操作了,它可以直接访问Input Attachment,很方便地去做它的Shading操作,最终生成需要的图像。

打开网易新闻 查看更多图片

第二种方法可以有效地降低Store和Load操作之间所产生的CPU和GPU同步的消耗,也可以有效地减少带宽消耗,因为不需要存储,也不需要第二次把这些存储的结果装载到你的GPU里面去,它完全是存在GPU的Tile Base内存当中的。

目前我们可以看到,single其实使用延迟渲染的案例非常的少,几乎没有。但实际上除了延迟渲染,Subpass对传统的服装渲染也是有优化的。

我们这边展示的一个案例,就是在Unity中很常见的Renderpass操作。第一个Renderpass去渲染不透明的物体,第二个就渲染透明的物体。前后由于他们的attachment其实是一样的,第二个Renderpass实际上要依赖于第一个Renderpass里面的Depth信息,所以它就需要一次存储和一次读取。

同样,我们使用Subpass把这两个Renderpass结合到一块去,第一个Subpass负责渲染不透明的物体,这个时候第一个Subpass已经把深度信息存在Tiled内存当中去了,我们最后就可以从Tiled内存当中直接获取,第二个Subpass就可以从这些内存中直接获取到Depth信息,最后渲染出最终的图像。

打开网易新闻 查看更多图片

可以看到这跟前面的例子一样,可以减少中间的存储、读取等操作,同时也可以减少在这个过程中产生的带宽消耗。这在传统的API里面,是很难实现的。

今天我的演讲也就到此为止,也感谢各位的支持,同时也感谢Unity能够给我们这样的机会,跟大家共享一下我们优化的工作以及原理。也祝愿各位开发者,能够在以后的工作中,在Unity引擎强大功能的帮助下,能够为我们的市场推出更多的爆款游戏,谢谢!

获取更多信息

Unity 技术精讲

[1]

[2]

[3]

[4]

[5]

打开网易新闻 查看更多图片

Unity 官方微信

第一时间了解Unity引擎动向,学习最新开发技巧