Windows 游戏的首要问题

Microsoft Windows 游戏和图形技术开发人员关系组每年对许多 Windows 游戏执行性能分析。 在这些会话中,我们将获得实践经验,以将我们每天收到的开发人员反馈和查询联系在一起。 有时,我们会帮助跟踪游戏中的神秘崩溃或其他问题,从而让我们进一步了解开发人员遇到的问题。

本文重点介绍我们在当前一代电脑游戏中遇到的许多常见问题。

CPU-Limited性能

绝大多数游戏都受具有高性能图形处理单元 (GPU) 系统上的 CPU 性能的限制。 这有时是由于对绘图提交使用批处理不当,但更常见的是,这是由于其他游戏系统消耗了大部分可用 CPU 周期。 在我们已将 GPU 视为限制的少数情况下,原因是高填充率或像素着色器需求、高分辨率设置或视频卡的顶点着色器性能较低。

由于大多数游戏都受 CPU 限制,因此最大的性能胜利来自优化 CPU 密集型游戏系统。 通常,AI 或物理系统以及相关的碰撞检测逻辑是运行良好的 Microsoft Direct3D 应用程序中 CPU 周期的主要使用者。 改进这些系统的任何工作都可以提高游戏的整体性能。

糟糕的批处理管理

若要使用 GPU 实现良好的并行度,需要绘制批处理包含足够的几何图形,并且着色器具有适当的复杂性,以使视频卡繁忙,同时不要使用过多的批来使命令缓冲区被淹没。 在当前一代硬件上,建议每帧提交大约 300 个或更少的绘图批处理提交, (低性能 CPU) 少提交,以防止驱动程序对命令缓冲区的处理成为性能瓶颈。 其他一些 API 状态调用和驱动程序组合可能会导致 CPU 处理成本高昂 (驱动程序编译着色器(例如) ),因此强烈建议进行常规性能分析。

复制内存过多

在大多数电脑游戏的开发过程中,开发人员使用方便的数据结构和字符串进行内容管理。 字符串比较、复制和其他操作所需的 CPU 工作通常具有可度量的开销,尤其是在考虑与缓存和内存子系统关联的性能命中时。 在开发这些系统时,应制定计划,以便在产品进入主要测试和发布阶段后删除或最大程度地减少对字符串处理的依赖。

过度使用动态绘图提交

处理静态数据时,新式视频硬件性能良好。 高端适配器通常具有大量的视频内存,但动态数据无法有效利用此内存。

虽然动态顶点缓冲区/索引缓冲区的合理高效使用模式可以为动态内容实现,但许多游戏会过度使用此成语来表示静态内容。 我们最常看到二进制空间分区 (BSP) 树和基于门户的系统,这些树和基于门户的系统将几何存储在数据结构中,这些数据结构不会映射到硬件,并且必须处理到每个帧的缓冲区中。 将尽可能多的内容放入静态资源可以大大减少将数据传输到视频卡的带宽开销,更好地利用板载 VRAM,并减少处理此内容所涉及的 CPU/缓存开销。

文件处理中的高开销

电脑游戏因加载时间长而声名远扬,尤其是与具有严格加载时间要求的主机游戏相比。 我们对许多游戏使用文件子系统的方式的分析揭示了一些常见问题。

打开文件的开销通常远高于开发人员的预期。 随着按需病毒扫描程序的广泛使用以及 NTFS 的其他功能,打开文件是一项相当昂贵的操作。 因此,一次性打开多个文件或重复打开和关闭同一文件是处理文件管理的糟糕方法。 某些游戏尝试通过在打开文件之前测试文件是否存在来降低此性能成本。 现实情况是,测试 NTFS 上是否存在文件需要打开文件,因此在打开前进行测试会导致支付两次费用。

允许加载项修改或修改的游戏,或者仍然包含用于替代数据文件检查的开发基架的游戏,由于检查这些文件,加载游戏时可能会显著延迟,即使这些文件不存在也是如此。 我们建议在使用特殊命令行开关或其他模式指示器运行时,游戏仅对这些文件检查,以便只有使用此功能的用户才能实际支付这些 (通常进行大量) 检查的性能成本。

可通过以下方法从文件系统获得其他性能:

  • 适当使用文件系统提示FILE_FLAG_RANDOM_ACCESS和FILE_FLAG_SEQUENTIAL_SCAN
  • 调整缓冲区大小以避免大量调用 OS 的读/写 API
  • 异步访问文件
  • 在后台加载线程

我们还强烈建议在生成或安装时) 脱机转换数据 (,而不是在首次运行游戏时依赖转换,因为这样做会对每个用户征收大量的性能税。

安装缓慢且令人沮丧

我们看到的另一个常见问题是许多新式电脑游戏需要很长时间的安装时间。 安装程序会多次提示用户,有时只是为了告诉用户,例如,“你不需要安装 DirectX”。通常,这些有问题的安装程序要求用户在游戏实际开始安装之前多次选择“ 下一步 ”或“ 确定 ”。 一旦它开始,我们发现一些游戏需要一个小时或更多时间,用户才有机会玩游戏。 我们强烈地认为,游戏体验的第一个小时不应该是安装。

建议采用多种方法来处理安装。 首先,使提示保持简单和最少。 其次,构建游戏数据,以便尽可能直接从分发磁盘使用部分或全部数据文件 - 新式 DVD 驱动器具有非常高的带宽。 第三,请考虑在游戏中实施按需安装,以减少或消除安装过程,并允许用户尽快进入游戏。 (有关按需安装的详细信息,请参阅 Games 按需安装。)

有关游戏安装的更多建议,请参阅 简化游戏安装

缺乏对物理内存的考虑

由于市场上电脑硬件的可变性很大,游戏通常利用即席配置测试来为图形详细信息级别选择默认设置。 我们看到的一些游戏在这些测试中使用了视频内存大小,但未能将此大小与物理内存大小相关联。 为了处理丢失设备的情况,卡上的大多数视频内存 (本地 VRAM 和非本地 AGP 内存孔径) 必须通过使用托管资源或自定义数据结构来支持物理内存。 一些高端视频卡的 VRAM 大小与低端 CPU 内存大小相媲美。 如果系统的物理内存与视频卡相比有限,则大部分 VRAM 无法有效利用,应配置较低的详细信息设置。

Real-Time音频采样率转换Over-Reliance

我们所看到的 CPU 周期消耗的另一个常见源发生在音频系统需要在混合期间将播放速率转换为硬件缓冲区时。 使用 Windows 驱动程序模型 (WDM) 驱动程序,硬件缓冲区格式不受应用程序直接控制,因为它是内核级资源;而是根据所有源的最高质量格式和硬件的功能来选择格式。 默认情况下,Windows XP 对此过程使用高质量的采样率转换,如果大多数音频样本需要速率转换,则将消耗相当一部分 CPU 周期。

建议使用相同的采样率创建所有 DirectSound 缓冲区。 如果使用 Microsoft Win32 waveOut 函数,则应对这些函数使用一致的采样率。 使用 WDM 驱动程序时,所有缓冲区将由内核混合,如果对其中一些缓冲区使用更高的采样率,则其余所有缓冲区的采样率将转换为匹配。 请注意,这意味着对所有音频样本使用相同的播放速率,包括任何流式处理音频解压缩缓冲区。 除非以 Windows 98 或 Windows Millennium Edition 为目标,否则设置主缓冲区速率不起作用。

注意

在 Windows Vista 及更高版本的操作系统上,DirectSound 和 waveOut 对所有音频输出使用 Windows 音频会话 API (WASAPI)

 

虚拟内存碎片

我们最近看到了许多与进程内存空间的 32 位限制相关的问题。 虽然用户模式进程的 2 GB 虚拟地址空间在历史上已经足够,但大量使用大型内存映射文件、自定义内存分配器和增加的 VRAM 大小 (必须映射到进程空间) 已经开始导致虚拟内存空间分配失败的情况。 某些非 Microsoft DLL 在虚拟地址空间中间使用固定启动位置,这会导致碎片导致分配失败。

当游戏使用尝试分配大量连续虚拟内存空间的自定义内存分配方案时,通常会出现这些问题。 建议编写分配器,以便它们根据需要请求更合理大小的虚拟地址空间部分。 例如,一次请求 64 或 256 MB,但不能请求 1 GB。 但是,应注意不要造成进一步的碎片。 64 位操作系统和硬件的出现将在未来极大地帮助这些问题,但必须小心处理当前一代 32 位系统。

操作Floating-Point控件Word

作为调试辅助,一些开发人员一直在通过对浮点控制字的操作,在浮点单元 (FPU) 上启用异常。 这样做存在严重问题,并可能导致进程崩溃。 就像调用约定要求保留 ebx 寄存器一样,大多数系统假定 FPU 处于默认状态,会给出合理的结果,并且不会生成异常。 驱动程序和其他系统组件通常会根据以下假设计算结果:标准错误值会出现在不良条件的寄存器中,但如果启用异常,这些异常将未经处理并导致崩溃。

Direct3D 将在调用线程的初始化过程中将浮点单位设置为单精度、舍入到最接近的浮点单位,除非使用 D3DCREATE_FPU_PRESERVE 标志,在这种情况下,浮点控制字保持不变。 由于控制词是每线程设置,因此确保所有应用程序线程都设置为单精度模式可以优化性能。 请记住,调用 _control87 对 x64 本机编码无效,后者专门使用 SSE,而且在基于 PowerPC 的 Xbox 360 CPU 体系结构中,成本极高。

注意

如果修改控件字,请使用 _controlfp_s ,请注意,对于 x64 平台,不能通过控件字更改浮点精度。

 

在需要具有不同舍入规则或其他行为(例如处理软件顶点着色器或编译)的任何库中,我们保存并还原控件字。 如果游戏需要使用非标准舍入或 FPU 异常,则应保存并还原浮点控制字,并且应确保它不会调用任何尚未证明可避免这些问题的外部代码,包括系统 API。

DirectX 运行时的可选安装

许多游戏会询问用户是否安装 DirectX。 如果用户假定系统安装了最新的 DirectX 可再发行组件,并且跳过了安装,然后安装会继续成功,这可能会导致问题。 如果游戏需要特定版本的 D3DX 或未安装的其他更新功能,则游戏将不起作用,并且用户将非常沮丧。

强烈建议游戏的安装程序以无提示方式安装生成游戏所针对的 DirectX 可再发行组件。 DirectX 安装过程旨在验证是否需要更新任何内容,如果不需要更新,则快速返回。 因此,无需询问用户如何安装 DirectX。

DirectX 的无提示安装可以通过从安装包运行此命令来完成: dxsetup.exe /silent

此外,可再发行文件夹的实际大小可以配置为仅包含游戏目标平台和使用情况实际需要的那些内阁文件 (.cab) 。

注意

在使用 dxsetup 之前,请阅读 不是直接安装

 

线程同步的过度使用

分析游戏时,通常会发现热门热点与进入和离开关键部分相关。 随着多核 CPU 的普及,游戏中多线程的使用急剧增加,许多实现依赖于大量使用线程同步。 即使没有任何争用,占用关键部分的 CPU 时间也相当长,并且所有其他形式的线程同步都更加昂贵。 因此,必须注意尽量减少使用这些基元。

游戏中过度同步的一个常见来源是使用 D3DCREATE_MULTITHREADED。 此标志虽然使 Direct3D 线程安全用于从多个线程进行呈现,但采用非常保守的方法,导致高同步开销。 游戏应避免使用此标志。 相反,构建引擎,以便与 Direct3D 的所有通信都来自单个线程,并且线程之间的任何通信都直接处理。 有关设计多线程游戏的详细信息,请参阅在 Xbox 360 和 Microsoft Windows 上为多核编码一文。

RDTSC 的使用

不建议使用 x86 指令 RDTSCRDTSC 无法正确计算某些动态更改 CPU 频率的电源管理方案和许多多核 CPU 上的计时,这些 CPU 的周期计数器在内核之间未同步。 游戏应改用 QueryPerformanceCounter API。 有关 RDTSC 问题以及使用 QueryPerformanceCounter 实现高分辨率计时的详细信息,请参阅 游戏计时和多核处理器一文。