Ultrabook™ 设备的遊戲優化





5.00/5 (2投票s)
在本文中,您将学习如何提高3D游戏的速度,并了解将应用程序移植到超极本系统时应注意的事项。
英特尔®开发人员专区提供用于跨平台应用开发的工具和操作方法信息、平台和技术信息、代码示例以及同行专业知识,帮助开发人员进行创新并取得成功。加入我们的物联网、Android、英特尔®实感™技术和Windows社区,下载工具,获取开发套件,与志同道合的开发人员分享想法,并参与黑客马拉松、竞赛、路演和本地活动。
相关文章
面向第四代英特尔®酷睿™处理器的英特尔®处理器显卡开发人员指南
触摸和传感器
如何创建可用的触摸UI
如何调整触摸控件
1. 引言
最近,我负责为游戏开发者大会准备一个我一直在开发的游戏引擎。考虑到活动的重要性,我需要我的游戏在我手头的三个设备上运行速度快,这些设备从当前的超极本™技术到两代前的系统不等。
在本文中,您将学习如何提高3D游戏的速度,并了解将应用程序移植到超极本系统时应注意的事项。无论您是经验丰富的游戏开发者还是刚刚进入该行业的业余程序员,您无疑都会认识到性能的重要性。一个以超流畅帧率运行的游戏会比一个以每秒五帧(FPS)的低速度运行的游戏感觉更精致和专业。再华丽的画面也无法掩盖您的游戏步履蹒跚、因持续错过显示器的垂直同步步骤而撕裂屏幕,并将游戏物理推入纯粹的混乱之中。通过这个实际游戏项目移植的案例研究,我希望您能深入了解可能遇到的实际问题和可能的解决方案。
本文重点介绍了一些常见的性能损失原因,并专门帮助游戏开发人员将典型的 AAA 级高端 3D 游戏移植到 Ultrabook 设备上,以满足现代观众对性能的要求。此类游戏通常需要高端独立显卡才能良好运行,并对 GPU 提出极高的要求。了解专用 GPU 和集成 GPU 之间的架构差异会有所帮助,但提高图形性能的最佳方法是分析管道中的瓶颈,并在不影响视觉质量的前提下优化这些区域。
您应该对图形API调用有基本的了解,熟悉构成典型3D游戏的组件,并了解或使用超极本。
2. 为什么性能很重要?
随着应用程序和游戏市场的日益拥挤,产品的独特卖点对于商业成功变得越来越重要,而性能在今天不仅是可取的,更是绝对必要的。许多用户甚至认为您的游戏只有在他们的设备上流畅稳定地运行后才算完成,并且不会在最初的负面体验之后继续玩游戏。
鉴于此要求至关重要,以及移动设备、平板电脑和便携式计算设备正在迅速增长,您会意识到性能至关重要。将您的游戏适配到超极本时,您可能会自满,因为它比其他设备拥有卓越的性能,但用户将要求最高标准并期望获得高端游戏体验。
从技能发展的角度来看,您现在所做的每一个优化和改进游戏代码的努力都将成为一项重要的经验,可以应用于未来的项目,使您成为一名更优秀的游戏开发者。
3. 为什么要优化?
许多开发者使用台式PC系统来创建和测试他们的3D游戏,独立显卡的存在有时会给人一种资源丰富的错觉,导致算法和着色器突破GPU的极限。当您在更受限的平台上运行此游戏时,它可能无法按预期运行,导致性能急剧下降。超极本是功能强大的移动设备,但它们无法提供与下一代高端GPU相同的原始渲染能力。此外,超极本设计用于移动使用,因此您的游戏很可能在电池供电下运行,需要高效的渲染管道以防止电量快速流失。您创建游戏内视觉效果的方法必须尊重这些事实。
在开发应用程序时,开发人员通常从顶部开始,然后向下裁剪,以便在可用时间内尽可能多地在设备上运行。
在超极本上开发并将游戏移植到由专用显卡驱动的台式机上是最简单的途径,因为这几乎消除了移植的需要。但是,您可能会发现自己正在与那些将质量标准设置得高得多的游戏竞争。这种方法有一个优点:您从一开始就关注电池续航时间,因此,您更有可能开发一个在游戏特定时刻(如标题屏幕和HUD页面)降低密集活动的3D游戏。在台式机上开发并优化到超极本更常见,并且通常会产生更高水平的质量,因为您的原始开发理念目标很高,然后想办法在更多外形尺寸上实现它。
4. 台式机到超极本 — 性能案例研究
我的故事始于GDC盛会前的数周,当时我正在一台相对现代化的PCI Express* 3.0显卡上运行我的游戏,该显卡价值约200美元,在最高画质设置下能达到60 FPS。这绝不是一个高端游戏装备,但它能够以最高设置运行任何3D游戏,没有明显的延迟,并且凭借其六核、6 GB系统内存和一系列超高速SSD硬盘,它表现出色。我知道活动中不会有台式机等着我,我也不想拖着一个巨大的PC系统半个地球。自然,解决方案是带上我的超极本,这是我拥有的第二强大的设备,足以进行一场精彩的展示。
我的超极本配备第四代英特尔®酷睿™处理器和英特尔®核芯显卡4000™,是我出差时的首选设备。我的首次测试很痛苦,掉了太多帧,以至于整个尝试似乎过于雄心勃勃。当前版本的3D游戏引擎严重依赖着色器和多目标渲染,像糖果一样吞噬CPU周期,并以尽可能快和响亮的速度运行一切。可以想象,这样一个庞然大物与便携设备上您想要的省电、友好的应用程序相去甚远。
尽管计划大胆,但我也知道现代超极本是非常有能力的游戏系统,如果使用得当,其生产力可以与台式机媲美,方便性更是超越。我还玩了很多在超极本上运行良好的游戏,任务并非不可能,所以我开始努力将FPS提高到所需的60帧——这是我GDC活动的目标。
作为一名老派程序员,我在性能分析器和图形调试器出现之前就学会了编程,因此我检测瓶颈的主要方法是移除引擎的很大一部分,直到性能得到改善。通过选择性地重新引入关键代码块,我可以确定引擎的哪些部分最慢。一旦瓶颈被识别,并且由于无法完全移除它们,便可以开始仔细地降低组件强度的过程。典型的例子是在着色器中跳过超出玩家特定范围的像素的法线贴图计算,或者每隔一个周期跳过AI更新调用以减少这些过程的开销。累积起来,这些小的改进开始累加,很快游戏引擎再次以全速运行,几乎没有视觉质量损失。
对于刚接触性能调优世界的程序员,我强烈建议您避免使用这种方法来检测瓶颈。有许多工具可以帮助您识别应用程序中的性能问题,这些工具不仅提供瓶颈的位置,还提供问题的性质。其中一套免费工具是英特尔®图形性能分析器,它会在您的应用程序运行时对其进行配置文件分析,并为您提供程序正在做什么以及完成它需要多长时间的快照。在活动中演示游戏时,我发现了一些问题,后来我修复了这些问题以提高最终结果的性能和流畅度。
如您在图 5 中所见,我从 20 fps 提升到 62 fps,前后场景的视觉差异很小。“之后”的截图显示移除了玩家周围的强烈动态照明,并使用了更不激进的片元着色器。
耗资源的着色器
我们很快意识到,最大的性能消耗来自图形渲染步骤。
如您在图 6 中所见,面板中标记为“渲染”的水平条消耗了我们大部分可用周期,当我们深入到细节时,很明显将对象渲染到屏幕上非常耗费资源。由此,我们很快意识到,一个渲染数十万个多边形(每个多边形都使用重型片元着色器)的场景会极大地导致性能损失。它到底消耗了多少?通过在着色器中添加 MEDIUM 和 LOWEST 技术,并缩减每像素的视觉效果,我们获得了六倍的性能提升。
为了确定LOWEST和MEDIUM实际做了什么,我们首先必须确定游戏的最低共同特征。通过找出哪些功能对于玩游戏来说是绝对必要的,然后忽略剩下的,我可以在着色器中创建新的LOWEST技术。早期,这种技术非常简单,几乎所有元素都被移除,包括所有阴影、法线贴图、动态照明、纹理叠加、镜面贴图等等。从接近零开始,可以运行游戏并查看此着色器在超极本上运行的“最佳情况”。当我将HIGHEST设置的屏幕截图与LOWEST设置的屏幕截图进行比较时,我看到了最重要的缺失成分,这会使用户在降低设置时感到痛苦。着色器中最不微妙的元素是阴影和纹理叠加,它们各自在缺失时会造成质量的急剧下降。重新添加叠加层相对便宜,我可以通过简单地将此元素的着色器代码添加回去并再次运行游戏来测试成本。另一方面,阴影付出了高昂的代价,无论是它们在引擎的另一部分中的生成还是它们在着色器本身中的使用。鉴于这方面对保持视觉质量的重要性,我们花费时间研究了各种方法,直到找到一种更快的解决方案,我将在下面详细介绍。
为着色器生成 MEDIUM 技术设置要容易一些,只需在最高和最低设置之间编写一个着色器,但始终倾向于性能。此设置的目的是允许最低设置的所有速度优势,但包含成本较低的效果,例如玩家手电筒、动态照明和稍好的阴影。
如果我简单地从最低设置中移除所有视觉质量,我就可以一次性获得所需的所有性能提升,但玩家们讨厌糟糕的图形几乎和讨厌糟糕的性能一样多。通过努力保留最高设置90%的视觉保真度,并优先考虑哪些方面可以减少或消除,我以最小的视觉质量损失实现了显著的改进。从5 FPS提升到40 FPS以上是我最大的单一改进。
在调查您的台式机游戏在超极本上运行缓慢的原因时,我强烈建议您拆解您的图形渲染管道,并认真思考时间都花在了哪里。您可以尝试我“大刀阔斧”的方法,移除大量功能直到您的管道得到改善,或者您可以选择更复杂的方法,使用性能分析工具。无论您选择哪种方法,一旦问题被定位,您最重要的任务就是找到一个解决方案,它不仅能提高该元素的运行速度,而且不会牺牲视觉质量。
为了给寻找这些最佳解决方案所需的工作提供一些启发,下面是我为解决我发现的一些瓶颈而设计的一些技术。
更便宜的阴影
为了解决上述阴影问题,我不得不寻找“级联阴影贴图”技术的替代方案。该技术在此不作详细讨论,但您可以在此处找到更多信息:http://msdn.microsoft.com/en-gb/library/windows/desktop/ee416307(v=vs.85).aspx。基本前提是,绘制四个渲染目标,其中包含玩家相机视野内所有物体的阴影,每个目标具有不同的细节级别。
着色器随后被指示根据屏幕上的像素是否落入先前计算的阴影中来重新着色。问题在于,这是一种高强度着色器效果,需要大量的视频内存。您会注意到在下面的“片元着色器”代码中,IF 分支语句被多次使用,并且一些 GPU 硬件会为每个使用的 IF 分支带来性能损失。在极端情况下,一些系统会计算像素输出的每种排列,这意味着分支代码没有任何好处。
fPercentLit = 0.0f;
if ( iCurrentCascadeIndex==0 )
{
fPercentLit += vShadowTexCoord.z > tex2D(DepthMap1,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
}
else
{
if ( iCurrentCascadeIndex==1 )
{
fPercentLit += vShadowTexCoord.z > tex2D(DepthMap2,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
}
else
{
if ( iCurrentCascadeIndex==2 )
{
fPercentLit += vShadowTexCoord.z > tex2D(DepthMap3,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
}
else
{
if ( iCurrentCascadeIndex==3 && vShadowTexCoord.z<1.0 )
{
fPercentLit += vShadowTexCoord.z > tex2D(DepthMap4,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
}
}
}
}
重要的是要减少视频内存需求和对 IF 分支语句的依赖。解决方案(有很多种)是创建一个单一的大型阴影巨型纹理,并将最低细节级别的阴影结果存储到此目标中。
一种新的更便宜的着色器技术被编写出来,它只需从这个阴影巨型纹理中读取,而无需任何 IF 语句。再次强调,该技术的具体细节超出了本文的范围,但首先识别性能下降的原因,然后创建第二种技术以在不牺牲成本的情况下产生相似的视觉效果这一基本实践是一种可靠的策略。
保持视觉保真度
优化引擎时要记住的一件事是在开发的每个阶段保护游戏的视觉质量。为了性能而简单地砍掉精美但昂贵的效果很容易,但将每个问题视为在保持游戏所需视觉质量的同时获得更好性能的机会则更具回报。您不仅会达到您想要的结果,而且您的游戏在高端系统上会运行得更好,这当然意味着随着游戏的扩展,您可以添加更多功能。
当你在桌面开发时,你会被诱惑使用巧妙复杂的片元着色器来创建各种表面效果,而简单地将它们移除以使用低端技术会极大地破坏最终图像的外观,以至于它不再像原始图像。如果你想保持游戏的完整性,在所有着色器技术中保持一致的视觉风格至关重要。新用户,被在线杂志中令人惊叹的屏幕截图所吸引,当他们运行你的游戏并看到明显不同的东西时,会感到非常失望。
在可能的情况下,寻找使用低技术手段(例如预烘焙纹理)来重现高端着色器效果的技术,甚至更好的是,将昂贵的像素效果限制在靠近玩家的区域。
把大部分精力花在你身边的人身上
听起来像是很好的家庭建议,但当你想让着色器在超极本上看起来很棒时,这是一个很好的策略。只需一个 IF 分支语句,你就可以判断正在计算的像素是否靠近玩家。如果是,你可以像以前一样使用昂贵的高端着色器像素效果,超出该范围,你可以恢复到更便宜的烘焙或伪造效果。
与上述方法协同使用的一种好技术是混合,只需额外增加一个 IF 分支,您还可以检查像素是否位于两个范围点之间。在最接近的两个范围内,您使用昂贵的效果,超出最接近的范围点,您计算廉价的效果。在第一个和第二个最接近的范围点之间,您计算两个结果之间的混合过渡。需要注意的是,这两个点之间的范围应该相对较窄,以避免双重计算成本。混合范围应该足够宽,以使玩家察觉不到过渡。在下面的代码中,您可以看到每个像素如何根据与视摄像机的距离进行处理,并且在 400 到 600 个单位的范围内,两个代码分支都会被计算。
float4 lighting = float4(0,0,0,0);
float4 viewspacePos = mul(IN.WPos, View);
if ( viewspacePos.z < 600.0f )
{
// work out surface normal per pixel
lighting = lit(pow(0.5*(dot(Ln,Nb))+0.5,2),dot(Hn,Nb),24);
}
if ( viewspacePos.z > 400.0f )
{
// cheapest directional lighting
lighting = lerp ( lighting, cheaplighting, min((viewspacePos.z-400.0f)/200.0f,1.0f) );
}
结果令人惊讶地好,渲染时创建了一个柔和几乎不引人注意的过渡。对于游戏来说,场景中大约90%的部分现在使用了廉价效果,从而加速了游戏的速度。
从进程内到预处理
在图形优化方面花费了大量时间后,我们的FPS仍然比目标60帧低了几帧。视觉质量和可实现性能之间的平衡已达成,但着色器系统之外的游戏引擎其他部分正在造成足够的处理开销,从而降低了游戏速度。
游戏引擎已经有一个内部性能指标系统,可以粗略测量整个游戏引擎管道的每个主要部分。除了图形指标,引擎还测量 AI、物理、武器、调试和遮挡等所需的时间。其中一个指标监测实时草地生成,它允许引擎为游戏提供无限草地的幻觉。一旦我们降低了图形处理的成本,我们注意到这个过程的相对成本作为游戏引擎管道中下一个最耗费资源的元素而跳升。当你进行优化时,你应该始终注意这些性能峰值,如果你确定它们使用了不合理的游戏周期,那么就需要仔细检查。知道什么是合理的通常取决于经验和对整个引擎的深入理解,在这种情况下,草地不应该消耗超过总游戏周期的10%,因为有这么多其他重要的服务需要游戏周期。在台式PC上,这个峰值不明显,但在超极本上,它是一个很大的性能瓶颈。除了指标峰值,在玩游戏时很明显,每当在玩家前面生成新的草地时,帧率就会卡顿,因为峰值打断了游戏的正常流畅运行。
解决方案,也是优化程序员的另一个重要法宝,就是将整个草地生成系统转移到游戏开始前的预处理步骤。草地不再是即时生成的,而是简单地移动到玩家前方,以创造一个几乎相同的效果。什么都不需要生成,只需移动即可,超极本松了一口气,因为宝贵的 CPU 周期被释放出来供游戏引擎的其余部分使用。我也松了一口气,因为魔术般的 60 FPS 达到了,游戏以所需的速度运行。
神秘的卡顿现象
在成功实现理想的游戏速度,并远渡重洋,将游戏和引擎呈献给GDC参会者们严苛的目光后,我发现在展会设备上安装游戏时,出现了一种奇怪的卡顿现象。这种卡顿在台式开发机上不存在,在我用于展前测试的超极本上也没有发生,但却在这些展会设备上出现了,更令人感兴趣的是,这些设备比我测试过的设备性能更强。
经过一番争论和回国后的研究,问题与“内部计时器分辨率”有关。简而言之,所有以机器无关速度运行的游戏(即游戏中的玩家从 A 点跑到 B 点所需时间相同,无论您在什么机器上运行游戏)都需要访问 GetTime() 命令。有几种可供选择,但最流行的一种是 timeGetTime() 命令,它返回自机器开机以来经过的毫秒数。它暗示您将以 1 毫秒的粒度获得结果,事实上许多台式机系统以这种分辨率报告时间。碰巧的是,在超极本和其他便携式省电设备上,这种粒度并非固定不变,可能会返回 10-15 毫秒范围内的分辨率。如果您使用此计时器来控制物理(我们的游戏引擎就是这种情况),结果是物理更新调用会从一个报告时间不规则地跳到另一个报告时间,导致看似随机且不稳定的卡顿。
粒度可以从1毫秒变为10-15毫秒的原因是,如果某些系统降低处理器频率,可以节省电池电量,而这种做法的副作用之一是计时器滴答的频率会变得不可预测。有许多解决方案,我们选择并推荐的是使用QueryPerformanceTimer()命令,它通过提供第二个返回计时器操作频率的命令来保证返回时间值的粒度。
5. 技巧与提示
要做的事
- 为超极本优化时,用额外的技术增强着色器,而不是替换它们。您的游戏仍需要在台式机和超极本上运行,而使用单个游戏二进制文件进行分发会容易得多。DirectX* 和 OpenGL* 着色器都允许您在单个着色器中创建技术。有了额外的技术,您的游戏代码可以检测您正在运行的平台,并选择最佳技术,无论是为了性能还是图形质量。
- 向用户提供选项屏幕,以便他们可以选择所需的性能/质量级别,因为这是当今大多数游戏玩家所期望的。根据系统规格检测并预选最佳设置始终是个好主意,但它应该始终可更改,并且您选择的默认设置应该始终在用户的系统上工作。
不要做的事
- 不要以为你必须以60 FPS运行你的游戏。在大多数现代设备上,你可以将显示器刷新间隔设置为跳过一个甚至三个垂直同步信号,以在30 FPS下获得同样流畅无撕裂的屏幕显示。当然,它不会像60 FPS那样流畅,但如果你的游戏时序经过调整,游戏仍然会感觉流畅且非常可玩。
- 在开发游戏时,不要低估片元着色器的成本,尤其是在低性能显卡上运行时。如果发现游戏性能低下,请关闭或降级所有着色器使用,作为排除故障的一种方法。
- 不要为用户预选显示设备可能不支持的分辨率。使用 Windows* API 查询显示设备以获取兼容的默认分辨率。
- 不要认为timeGetTime()返回的时间间隔为1毫秒。当超极本省电功能启用时,它可能低至10-15毫秒!
6. 超极本陷阱简要介绍
这可能看起来是显而易见的练习,但这里有一个快速实用的指南,用于在超极本上测试、运行和展示您的游戏和3D应用程序。
省电
如果您正在向大量观众展示您的游戏,并希望以最佳状态展示,那么连接超极本电源至关重要。请勿使用电池供电,因为系统会通过调低您希望保持在“炽热最大”状态的各种硬件设置来保护自己。
作为额外预防措施,通过控制面板找到电源管理设置,并仔细检查在使用“插电”电源时,所有节能设置都已关闭,并且尽可能多的设置都设置为“高”。
图形
控制面板还有一个设置面板,可以访问您特定设备的图形加速器设置。您会找到在省电模式下控制 GPU 和驱动程序的设置。您必须将此设置设为“高性能”或等效模式,以确保您的板载 GPU 尽可能快地运行。
你可能觉得这些事情很奇怪,但超极本的设计宗旨是在每一个环节都节约电量,让你能够连续使用数小时。要在超极本上获得最佳性能,没有什么比插上电源并把所有设置调到“11”更有效的了。
后台任务
老手们会对此简单却关键的建议明智地点头,即快速扫描超极本在Windows启动时可能正在运行的任何后台任务。最初旨在作为轻量级且有帮助的后台任务,当它们结合在一起时,它们倾向于通过各种方式缓慢地占用CPU。
尽管其中一些任务至关重要,但当您演示您的 3D 游戏在超极本上运行有多快时,明智的做法是取消您在该会话中不需要的任何任务。不用担心,下次您启动超极本时它们会重新出现,但在 Windows 会话的剩余时间里,您的设备将专用于运行一个应用程序,那就是您的应用程序!
7. 结论
游戏优化是一个广阔的话题,开发者应该将优化视为日常职责的一部分。挑战在于让你的游戏能在尽可能广泛的硬件上运行,而这时经验和专业知识就派上用场了。使用英特尔®工具,如VTune™分析器和英特尔图形性能分析器,可以加速发现问题的过程。像本文这样的文章可能会给你一些可能的解决方案的线索,但最终还是取决于你横向思考的能力。你能用另一种方式来做这件事吗?有没有更快的方法来做这件事?有没有更聪明的方法来做这件事?这些都是开始这个过程的很好的问题,你问得越多,你就越擅长优化你的游戏和应用程序。正如我在本文开头所建议的,你不仅会成为一个更好的程序员,你还会将你的影响力扩展到一个以惊人速度增长的市场!
相关内容
Codemasters GRID 2* 在第四代英特尔®酷睿™处理器上的表现 - 游戏开发案例研究
并非一日建成 - 《全面战争:罗马 II》中吸取的教训
面向第四代英特尔®酷睿™处理器的英特尔®处理器显卡开发人员指南
感知计算:增强FPS体验
英特尔®开发人员专区提供用于跨平台应用开发的工具和操作方法信息、平台和技术信息、代码示例以及同行专业知识,帮助开发人员进行创新并取得成功。加入我们的物联网、Android*、英特尔®实感™技术和Windows*社区,下载工具,获取开发套件,与志同道合的开发人员分享想法,并参与黑客马拉松、竞赛、路演和本地活动。
本文档中重印的任何软件源代码均根据软件许可证提供,并且只能根据该许可证的条款使用或复制。
Intel、Intel 标识、Ultrabook 和 VTune 是英特尔公司在美国和/或其他国家的商标。
版权所有 © 2014 英特尔公司。保留所有权利。
*其他名称和品牌可能被声明为他人的财产。