案例研究:使用英特尔GPA优化《剑侠情缘三》游戏的性能_1脳1 scissor rect-程序员宅基地

技术标签: Performance Optimization  textures  英特尔  优化  游戏  网络游戏  图形  

 
2009年09月28日 10:00


郭胜(英特尔开发者关系部) 杨林(金山软件西山居游戏工作室)

介绍

游戏在集成显卡上的性能日益成为游戏开发者关注的一个重要问题。这主要是由于两方面的原因:一是集成显卡的功能日益增强,具有越来越强的3D图形处理能力,支持的3D游戏也越来越多【3】。其次随着个人移动平台(如笔记本电脑,上网本等)日益普及,低功耗、高性价比的集成显卡作为这些平台上的主要图形解决方案,将持续占据更重要的市场地位。Mercury Research 的报告显示,在 2008 年,集成显卡芯片组的销量有史以来首次超过独立显卡;到 2013 年,集成显卡和独立显卡的销量有望达到 3:1。因此,针对集成显卡优化游戏的性能,有利于提升游戏的用户普及度,吸引更多潜在玩家。

英特尔的图形性能分析器(GPA)可帮助游戏开发人员分析、评估和改进运行于英特尔集成显卡上的游戏性能【1】。GPA是一套基于 DirectX 的功能强大的工具套件,由系统分析器和帧分析器两项主要工具组成。它能收集系统平台和图形帧的性能数据,让您了解系统和单个帧的负载分布,并支持执行“假设性”实验,评估优化所能带来的潜在性能提升。

本文介绍了一个使用GPA在英特尔4系列集成显卡上分析和优化《剑侠情缘三》【2】网络游戏性能的案例。《剑侠情缘三》(简称《剑网3》)是金山公司历时5年自主研发的大型全3D网络游戏,也是国内知名游戏品牌“剑侠情缘”系列最新一部作品。依托获得国家863计划支持的、自主研发的游戏引擎,《剑网3》的即时演算效果已达到近似电影画面水准;人物细腻的细节展示、花海林间的光影表现等,都已达到国内网游顶级水准。

作为英特尔软件伙伴项目(Intel Software Partner Program)的成员,金山公司在该游戏开发过程中获得了英特尔大量的技术支持,为了使更多玩家能体验这款游戏,金山与英特尔在集成显卡的优化上进行合作。GPA在发现此游戏的性能瓶颈上发挥了重要的作用。优化的结果使原有的性能在英特尔4系列集成显卡上提升了近一倍,达到可玩的帧速率,使更多玩家能体验这款精彩的大型3D网络游戏。

性能分析准备

使用GPA测试游戏的性能前,需要设置两台PC。一台作为分析机,安装和运行GPA图形界面的分析工具;另一台PC作为目标机,配置英特尔4系列集成显卡,安装和运行游戏以及GPA服务端程序。两台机器通过TCP/IP网络互联。

为了便于测试,金山公司专门开发了游戏的显卡测试版本。此版本包含该游戏中大量典型的图形渲染特性。虽然《剑侠情缘三》是一款网络游戏,但此测试版本能自动运行在单机上,大大方便了性能分析。

环境部署好之后,要选择合适的游戏配置和一个性能上典型的游戏场景作为测试基准。在集成显卡上,我们使用缺省的最基本的游戏配置,分辨率定为800x600。运行游戏测试版本,我们找到一个在性能和场景复杂度上有代表性的场景,如图1所示。注意,Fraps工具在画面右上角显示此游戏的初始帧速率为11.

image029.jpg

图1:《剑侠情缘三》显卡性能测试版场景(此图经金山软件授权使用

测试环境和典型场景准备好以后,接下来将使用GPA的系统分析器和帧分析器对该游戏进行性能分析。

系统性能分析

GPA的系统分析器提供了一组状态覆盖模式,以及关于CPU、GPU和DX运行时的多组性能计数器。使用系统分析器能够从平台系统的角度分析图形渲染管线的瓶颈是否在上述一个或多个域中,并且帮我们判断是否必要使用帧分析器进行进一步分析(如果GPU中存在瓶颈的话)。

首先分析游戏的负载分布。GPA提供了几个状态覆盖模式可以用于评估游戏在图形渲染管线上主要阶段的负载。这几个状态覆盖模式是:

1. “Null Hardware”。此状态覆盖模式能把显卡上的负载去掉,也相当于把显卡的性能提升到无穷大。可以用于评估显卡负载对帧速率的影响程度。

2. “Null Driver”。此模式把显卡驱动以及其后显卡硬件上的负载都去掉,可以用于评估游戏应用层代码的负载对帧速率的影响程度。此模式的帧速率同时反映了不修改代码的情况下,游戏在任何显卡上(保持CPU和内存相同)的性能上限。

3. “1X1 Scissor Rect”。在IIG实现中,此模式几乎可以去除显卡Rasterization阶段后的所有负载。使用此模式可以评估象素相关的负载(包括纹理访问)对帧速率的影响程度。

下表是上述覆盖模式和正常模式下系统分析器显示的游戏帧速率和相应的帧时间:

覆盖模式

帧速率(fps)

帧时间(ms)

正常模式

11

91

1X1 Scissor Rect

19

53

Null Hardware

21

48

Null Driver

52

19

表1: 不同覆盖模式下的性能

根据表1,可以评估游戏渲染过程中四个阶段对整个游戏帧时间的影响(图2)。需要注意的是,图中显示的每个阶段的时间并不是它们实际处理每帧画面的时间,而是实际处理时间中对整个帧时间有影响的那部分。因为不同渲染负载通常会使这些阶段时而串行时而并行,所以它们的实际处理时间可能会更长。每个阶段的时间代表了它们的负载。图中红线代表此游戏优化的目标:20帧每秒或50毫秒每帧。

image033.JPG
图2:测试场景的渲染负载分布

根据表1和图2,可以得出以下推论:

1.游戏“Null Hardware”模式显著改善性能,此游戏的主要瓶颈在GPU。但图2显示CPU端的负载也很重,因此性能瓶颈可能存在于渲染过程的多个阶段中。

2.象素处理是主要瓶颈之一,对整个帧时间的影响最大。但仅从局部优化显卡上象素处理的负载并不能达到目标帧时间。

3.驱动的负载在渲染观察中仅次于象素处理。说明游戏每帧发送的渲染命令的数量和(或)数据拷贝等开销很大,需要重点关注DX的绘制调用方式。

4.根据“Null Driver”模式下的帧速率,此游戏场景在任何显卡上的性能上限是52帧。根据经验,通常这个值应该超过100。说明游戏应用层代码和DX运行时的负载较重。

5.渲染管线的整体负载比较重,需要把总的帧时间优化掉一半,才能达到目标帧时间。因此,必须从应用层开始进行全局优化,减轻整个渲染管线上各个阶段的负载。

因此接下来,我们需要分析游戏的DX绘制调用方式。GPA提供了一组DirectX层的性能计数器,可以统计程序每帧中的DX绘制调用、DX状态改变和DX锁调用的数量和时间。观察这些值有助于了解DX层的开销,以及分析DX调用行为对渲染管线后端的性能影响。

image034.jpg

图3:系统分析器采样的DX计数器的值

上图显示,每帧的绘制调用(DrawCall)大约为1500个,与其他的游戏比,这个值很高,意味着DirectX运行时的开销会比较重,以及每帧绘制的对象很多。每帧的DX状态变化数有约20000次,可算出平均每个绘制调用的状态变化数为13次,这个值比较低,因此状态变化对性能的影响不大。每帧中调用的DX锁和表面锁的总时间只有0.25毫秒,与整个帧时间91毫秒比几何可以忽略不计,因此锁的调用对性能的影响不大。以上分析指出:过多的绘制调用是导致整个渲染管线负载过重的主要原因之一。根据这个判断,接下来需要使用帧分析器分析这些绘制调用都做些什么。

单帧性能分析

GPA可以把渲染一个游戏帧需要的信息以及性能数据捕捉到一个文件中。帧分析器基于这个文件工作,可以回放场景的渲染过程,显示绘制调用的性能数据。用户可以修改绘制调用相关的渲染状态、着色器以及纹理MIP级别等,这些改变导致的绘制调用在GPU上的性能变化将显示在回放结果上。开发者使用帧分析器可对游戏帧每个绘制调用的性能进行分析。图4是使用GPA帧分析器分析此游戏的界面。
image036.jpg
图4:帧分析器的界面

此视图中,最上面的“渲染单位可视化面板”(图4 a)显示了渲染一帧的所有渲染单位的顺序和时间。渲染单位主要指三类DX调用:绘制调用(Draw Call),表面清除(Clear)和表面拷贝(Surface Copy)。每个渲染单位都用一个柱条表示,柱条的高度显示与此渲染单位关联的所有渲染操作(包括状态切换等)在GPU上的总时间。与“渲染单位可视化面板”对应的是左边中间的“系统概览面板”(图4 b)。此视图用表格形式显示每个渲染单位,以及相关的性能数据(如类型,绘制几何的数量,消耗时间,新老时间变化等)。可以按不同的性能数据对渲染单位排序。选择“渲染单位可视化面板”和“系统概览面板”中的条目,都会在左下方的“渲染目标面板”(图4 c)上显示当前渲染目标的状态,并且加亮选择的条目对渲染目标的改变。右下方的“表单面板”(图4 d)中会显示与所选条目相关联的各种资源和性能数据,以及着色器的汇编和HLSL形式的代码。用户可以随时更改这些数据(状态,纹理,着色器等),帧分析器会及时重新计算和更新界面,为用户评估新的性能。

开始分析游戏帧时,首先观察“系统概览面板”中的分区(Region)。分区是帧分析器按照渲染目标划分的。每个分区包含一组渲染单位。渲染帧的过程中,每切换一次渲染目标,就会产生新的分区。展开分区,可以看到“0to0”和“1to1”分区的作用是清除颜色和Z/Stencil缓冲。“2to655” 分区负载把水面反射的倒映绘制到纹理表面(图5)。最后的分区在帧缓冲中绘制整个场景。

image037.jpg

图5:产生水面反射纹理的分区

从图形界面底部的性能统计信息(红色矩形框中)可以发现,“2to655” 分区占用了41.4%的帧时间,几乎达到总时间的一半。但最后屏幕上却看不到水面倒映,因为河流还没有进入摄像机的视线范围,所以在此帧中,绘制水面反射倒映是冗余的。这是一个重要的暗示,说明水面反射有很大的优化空间。

image038.jpg

图6:根据GPU时间排序渲染单元

按照每个渲染单元的绘制时间排序,可以找到最耗时的一些渲染单元。在做任何实验之前,我们先按照OLD Duration降序重排所有渲染单元(图6)。“系统概览面板”显示第1250个绘制调用的开销最大,渲染目标显示这个绘制调用负责渲染地形。

image039.jpg

图7:选择使用地形着色器的所有绘制调用

使用鼠标右键点击地形绘制调用关联的着色器,可以把所有使用此着色器的绘制调用(同时把场景中所有地形绘制调用)找出来。图7显示所有地形绘制占用整个帧时间的10.8%。从绘制调用ID的连续性看,游戏基本上是按调用状态分类绘制的,这是游戏已采用的一个良好的编程技巧。

image040.jpg

图8:地形渲染的“SimplePixelShader”实验

然后做 “SimplePixelShader”实验,可评估优化地形色器程序后,地形渲染性能最多可以改进约48.3%。接着尝试做“2x2Textures” 实验,发现最多只能改进0.7%,因此地形渲染性能的优化的重点应该放在优化象素着色器程序的复杂度上。

其他前10个耗时的绘制调用中还包括对树叶的绘制。使用和分析地形渲染调用相同的方法,可以发现所有树叶绘制的开销占总的帧时间的21%(图9)。图中显示渲染树叶时没有用户定义的象素着色器。因此不需要做“SimplePixelShader”实验。

image041.jpg

图9:选择使用树叶着色器的所有绘制调用

通过“2x2Textures”实验,可评估减少树叶的纹理细节和尺寸,最多提升渲染树叶性能的41.3%(图10)。

image042.jpg

图10:树叶渲染的“2x2Textures”实验

使用“表单面板”的纹理表单,可以观察绘制树叶时使用的纹理(图11)。我们发现有一个分辨率为1024x1024的很大的纹理,而且此纹理被访问了42次。另外,其他几个树叶纹理只有颜色的不同,而树叶结构相同。通过检查这些绘制调用使用的着色器程序,发现这是一个建立树叶深度缓冲的调用,目的利用显卡的Early-Z Rejection功能。而真正的树叶绘制还在后面第二趟进行。这给我们一个优化的提示,由于只需要建立Z缓冲,因此只需要一个表示树叶结构的纹理即可,纹理颜色在本趟绘制中不是必要的。这样可以节省纹理带宽。

image043.jpg

图11:树叶渲染使用的纹理

按照图元数(Prim Counts)排序,可以查看不同批绘制调用的尺寸。比较绘制调用的尺寸和此绘制调用在屏幕上显示的大小,可以判断游戏程序是否进行了良好的LOD(Levels of Detail)优化。图12显示最大的批绘制包含1540个三角形,但在画面中显示很小的部分(渲染目标中粉红色高亮的部分),通过查看关联纹理等方法,可以判断这些绘制的对象属于人物模型,这说明模型网格没有做LOD优化。另外,合适的批绘制尺寸有利于减少绘制调用的开销和提高显卡的处理效率。IIG推荐的批绘制尺寸在200~1000个图元(primitive)。从排序结果中可发现此游戏中接近1/3的绘制调用的尺寸都小于200个图元。因此是否可以把部分零碎的小尺寸绘制调用合并成大尺寸的也是一个可选的优化考虑点。

image044.jpg

图12:按照图元数(Prim Counts)排序所有绘制调用

优化策略

根据GPA 发现的性能问题,我们使用了以下策略进行优化。

水面反射

为了实现逼真的水面动态光影效果,此游戏每帧都会渲染整个场景在水面反射的倒影,并作为一张纹理贴到河流网格上。渲染水面反射的开销非常大,几乎占用了一半的帧时间,有很大优化的空间。优化的方案如下:

1. 进行阻塞查询(Occlusion Query),当水面不可见时不绘制倒影纹理

2. 在水面可见情况下,仅当摄像机的角度和位移大于一定程度才重新绘制倒影纹理。

3. 水中的物体和物体在水面的倒影通常不需要非常清晰,特别是在有波浪的动态水面上,因此可使用低细节度的纹理、模型网格以及简单的着色器程序进行绘制。

4. 在低帧率的平台上关闭水面倒影的计算。

树叶

游戏中很大一部分时间用于绘制大量的树叶。帧分析器的实验显示,树叶绘制的瓶颈主要在纹理访问上。由于这趟绘制只是填充深度缓冲,因此采用的优化方案主要是减少使用的纹理,只用一张表示树叶结构的小纹理。从而降低纹理带宽。

地形

在测试场景中,地形在屏幕中占据的范围很大。帧分析器的实验显示,优化重点可放在简化象素着色器程序的复杂度上。我们通过简化纹理混合算法提高性能,并且LOD技术不仅用在减少远处对象的mesh细节,而且用在减少着色程序的复杂度上,甚至很远处仅使用一张纹理简单表示。

模型的LOD:

测试发现,一些远处对象的mesh并没有使用LOD技术降低细节度。虽然测试场景中人物不多,所以这种绘制开销没有造成严重的性能瓶颈,但这是一个潜在的性能问题。因此金山的开发者为复杂模型制作了多种细节的mesh。使得LOD技术能在游戏中应用。

image045.jpg

图13:优化后的测试场景(此图经金山软件授权使用

经过上述优化,游戏测试场景达到23帧每秒的帧速率(图13)。如此复杂的场景在4系列集成显卡上的性能几乎提高了1倍。这样的性能对保证《剑侠情缘三》的可玩性已经足够了,因为对于这款角色扮演游戏而言,服务器与客户端同步频率才每秒16次,因此玩家已能获得良好的游戏体验。

总结

在集成显卡市场上,英特尔集成显卡一直占据最大的份额。随着移动平台市场的增长,集成显卡在所有显卡市场中的比重越来越大。优化游戏在英特尔集成显卡上的性能,能扩大游戏的潜在销量。为了使广大游戏开发者能掌握英特尔图形性能分析器的主要功能、分析方法和优化技巧,本文介绍了一个在英特尔集成显卡上优化金山公司《剑侠情缘三》网络游戏的成功案例。我们使用GPA系统分析器的几个有用的覆盖模式分析了游戏渲染管线的负载分布。在使用GPA帧分析器时,我们通过分别按GPU时间和图元数排序找到了几个关键的性能瓶颈,同时我们使用多种实验评估了最有效的优化方向。灵活地使用GPA的丰富功能,大大节省了我们分析和优化游戏的时间。我们希望本文介绍的GPA的功能和分析方法能有助于优化您的游戏性能。

参考

[1] http://software.intel.com/zh-cn/articles/intel-gpa/

[2] http://jx3.xoyo.com/

[3] http://www.intel.com/support/graphics/sb/cs-012643.htm

作者简介

郭胜 英特尔开发者关系部门的应用工程师,主要负责为游戏独立软件开发商(ISV)提供英特尔技术咨询和性能优化服务。他拥有南京大学计算机硕士学位,擅长实时 3D 图形应用的软件设计、编程以及性能优化。

杨林 现任金山软件西山居游戏工作室高级开发经理,主要负责图形引擎的评估、构架和编程等多方面工作。杨林于2003年在浙江大学能源系毕业,专业方向为火力发电。后进入金山软件公司担任主程序的工作,负责西山居新一代网络游戏引擎以及网络游戏《剑侠情缘网络版三》的开发工作。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jjiss318/article/details/7162246

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签