Windows タイトルの上位の問題
Microsoft Windows Gaming and Graphics Technologies Developer Relations グループは、毎年多くの Windows ゲームのパフォーマンス分析を実行します。 これらのセッションでは、毎日受け取る開発者のフィードバックやクエリに結び付ける実践的な経験が得られます。 場合によっては、タイトル内の神秘的なクラッシュやその他の問題を追跡するのに役立ちます。これにより、開発者が発生している問題に関するさらに詳しい分析情報が得られます。
この記事では、現在の世代の PC ゲームで見られた一般的な問題の多くについて説明します。
- CPU 制限付きパフォーマンス
- バッチ管理が不十分
- 過剰なメモリ コピー
- 動的描画送信の過剰な使用
- ファイル処理のオーバーヘッドが大きい
- インストールが遅く、フラストレーションが高い
- 物理メモリの考慮の欠如
- Real-Timeオーディオサンプルレート変換への過度の依存
- 仮想メモリのフラグメント化
- Floating-Point コントロール Wordの操作
- DirectX ランタイムのオプションのインストール
- スレッド同期の過剰な使用
- RDTSC の使用
CPU-Limitedパフォーマンス
ゲームの大部分は、高性能グラフィックス処理装置 (GPU) を搭載したシステムでの CPU パフォーマンスによって制限されています。 これは、描画送信のバッチ処理の使用が不十分な場合がありますが、より一般的には、他のゲーム システムが使用可能な CPU サイクルの大部分を消費しているためです。 GPU を制限と見なした場合、原因は非常に高い塗りつぶし速度またはピクセル シェーダーの需要、高解像度の設定、またはビデオ カードによる頂点シェーダーのパフォーマンスの低下です。
ほとんどのタイトルは CPU に制限されているため、CPU 集中型ゲーム システムの最適化によって最大のパフォーマンスが得られます。 通常、AI または物理システムと関連する衝突検出ロジックは、適切に動作する Microsoft Direct3D アプリケーションの CPU サイクルの主要なコンシューマーです。 これらのシステムを改善するための作業は、ゲームの全体的なパフォーマンスを向上させることができます。
バッチ管理が不十分
GPU を使用して良好な並列処理を実現するには、描画バッチに十分なジオメトリが含まれている必要があります。また、シェーダーには適切な複雑さがあり、ビデオカードビジー状態を維持しながら、コマンド バッファーがフラッディングされるほど多くのバッチを使用しないようにする必要があります。 現在の世代のハードウェアでは、コマンド バッファーのドライバーの処理がパフォーマンスのボトルネックにならないように、フレームあたり約 300 個以下の描画バッチ送信 (低パフォーマンス CPU では少ない) をお勧めします。 その他の API 状態呼び出しとドライバーの組み合わせによっては、コストのかかる CPU 処理 (シェーダーのドライバー コンパイルなど) が発生する可能性があるため、定期的なパフォーマンス分析を強くお勧めします。
過剰なメモリ コピー
ほとんどの PC タイトルの開発中に、開発者はコンテンツ管理に便利なデータ構造と文字列を使用します。 文字列の比較、コピー、その他の操作に必要な CPU 作業には、多くの場合、特にキャッシュとメモリ サブシステムに関連するパフォーマンス ヒットを考慮すると、測定可能なオーバーヘッドが発生します。 製品がプライマリ テストおよびリリース フェーズに入ったら、文字列処理への依存を削除または最小限に抑えるために、これらのシステムを開発する際に計画を行う必要があります。
動的描画送信の過剰な使用
最新のビデオ ハードウェアは、静的データを処理するときに優れたパフォーマンスを発揮します。 多くの場合、ハイエンド アダプターには非常に大量のビデオ メモリがありますが、このメモリを動的データで効果的に利用することはできません。
動的な頂点バッファー/インデックス バッファーの合理的に効率的な使用パターンは動的コンテンツに実装できますが、多くのタイトルでは、静的なコンテンツに対してこのイディオムが過剰に使用されます。 ほとんどの場合、バイナリ空間パーティション分割 (BSP) ツリーと、ハードウェアにマップされず、すべてのフレームのバッファーに処理する必要があるデータ構造にジオメトリを格納するポータル ベースのシステムでこれを確認します。 できるだけ多くのコンテンツを静的リソースに配置すると、ビデオ カードにデータを転送する際の帯域幅のオーバーヘッドを大幅に削減し、オンボード VRAM をより適切に使用し、このコンテンツの処理に伴う CPU/キャッシュ オーバーヘッドを削減できます。
ファイル処理のオーバーヘッドが大きい
PC ゲームは、厳密な読み込み時間要件を持つコンソール タイトルと比較して、長い読み込み時間で評判を得ています。 多くのタイトルがファイル サブシステムを使用する方法を分析すると、いくつかの一般的な問題が明らかになります。
通常、ファイルを開くオーバーヘッドは、開発者が予想するよりもはるかに高くなります。 オンデマンド ウイルス スキャナーが広く使用されており、NTFS の追加機能により、ファイルを開くのはかなり高価な操作です。 一度に多くのファイルを開いたり、同じファイルを繰り返し開いたり閉じたりすることは、ファイル管理を処理する方法が低い方法です。 一部のゲームでは、ファイルを開く前にファイルの存在をテストすることで、このパフォーマンス コストを軽減しようとしました。 実際には、NTFS 上にファイルが存在することをテストするにはファイルを開く必要があるため、開く前にテストすると、コストが 2 回支払われます。
アドオンの変更や mod を許可するゲーム、またはオーバーライド データ ファイルのチェックへの開発スキャフォールディングが含まれているゲームでは、これらのファイルが存在しない場合でも、これらのファイルをチェックするため、ゲームの読み込みに大幅な遅延が発生する可能性があります。 特別なコマンドライン スイッチまたはその他のモード インジケーターを使用して実行する場合は、これらのファイルに対してのみゲームをチェックすることをお勧めします。これにより、この機能を利用するユーザーのみが実際にこれらの (多くの場合、広範な) チェックのパフォーマンス コストを支払います。
次の方法で、ファイル システムから追加のパフォーマンスを得ることができます。
- ファイル システム ヒントのFILE_FLAG_RANDOM_ACCESSとFILE_FLAG_SEQUENTIAL_SCANの適切な使用
- OS の読み取り/書き込み API への大量の呼び出しを回避するためのバッファーのサイズ設定
- ファイルへの非同期アクセス
- バックグラウンドでのスレッドの読み込み
また、ゲームの初回実行時に変換に依存するのではなく、(ビルド時またはインストール時に) オフラインでデータを変換することを強くお勧めします。そうすると、すべてのユーザーに大きなパフォーマンス税が課されるためです。
インストールが遅く、フラストレーションが高い
私たちが見てきたもう一つの一般的な問題は、多くの最新のPCゲームに必要な非常に長いインストール時間です。 インストーラーは、ユーザーに何度もプロンプトを表示します。場合によっては、ユーザーに "DirectX をインストールする必要はありません" などとユーザーに伝えることがあります。一般に、これらの問題のあるインストーラーでは、ゲームのインストールが実際に開始される前に、ユーザーが [次へ] または [OK] を何度も選択する必要があります。 開始すると、ユーザーがゲームをプレイする機会を得るまでに 1 時間以上かかるタイトルがいくつか見られます。 ゲーム プレイエクスペリエンスの最初の 1 時間はインストールであるべきではないことを強く感じています。
インストールを処理するには、いくつかの方法をお勧めします。 最初に、プロンプトをシンプルにし、最小限に抑えます。 2 つ目は、可能な限り、一部またはすべてのデータ ファイルをディストリビューション ディスクから直接使用できるようにゲーム データを設計することです。最新の DVD ドライブの帯域幅は非常に高くなります。 3 つ目は、インストール プロセスを減らすか排除し、ユーザーができるだけ早くゲームに参加できるように、タイトルにオンデマンドインストールを実装することを検討します。 (オンデマンドインストールの詳細については、「 Install-on-Demand for Games」を参照してください。
ゲームのインストールに関するその他の推奨事項については、「 ゲームのインストールの簡略化」を参照してください。
物理メモリの考慮の欠如
市場におけるPCハードウェアのばらつきが大きいため、タイトルは通常、アドホック構成テストを使用してグラフィカル詳細レベルのデフォルト設定を選択します。 これまでに見たタイトルの中には、これらのテストでビデオ メモリ サイズを使用しているものもありますが、これを物理メモリ サイズと関連付けるのに失敗しています。 紛失したデバイスの状況を処理するには、ビデオ メモリの大部分 (カード上のローカル VRAM と非ローカル AGP メモリ開口の両方) は、マネージド リソースまたはカスタム データ構造を使用して物理メモリによってサポートされる必要があります。 一部のハイエンドビデオカードには、ローエンドCPUメモリのサイズに匹敵するVRAMサイズがあります。 ビデオ カードと比較してシステムの物理メモリが制限されている状況では、そのほとんどの 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 MB または 256 MB を要求しますが、1 GB は要求しません。 ただし、さらなる断片化を引き起こさないように注意する必要があります。 64 ビットオペレーティング システムとハードウェアの出現は、将来的にこれらの問題を大きく助けますが、現在の世代の 32 ビット システムでは注意が必要です。
Floating-Point コントロール Wordの操作
デバッグ支援として、一部の開発者は浮動小数点制御ワードの操作を介して浮動小数点ユニット (FPU) で例外を有効にしています。 これを行うことは非常に問題であり、プロセスがクラッシュする可能性があります。 呼び出し規約で ebx レジスタを保持する必要があるのと同様に、システムの大部分では、FPU が既定の状態であると想定され、妥当な結果が得られ、例外は生成されません。 ドライバーやその他のシステム コンポーネントは、多くの場合、標準エラー値が悪い状態のレジスタに表示されるという前提に基づいて結果を計算しますが、例外が有効になっている場合、これらはハンドルされないままになり、クラッシュが発生します。
Direct3D では、D3DCREATE_FPU_PRESERVE フラグが使用されていない限り、呼び出し元スレッドの初期化の一環として、浮動小数点ユニットが単精度の最も近いラウンドツーニアスに設定されます。この場合、浮動小数点制御ワードは変更されません。 制御ワードはスレッドごとの設定であるため、すべてのアプリケーション スレッドが単精度モードに設定されていることを確認すると、パフォーマンスが最適化される可能性があります。 _control87の呼び出しは、代わりに SSE のみを使用する x64 ネイティブ コーディングでは有効ではなく、Xbox 360 CPU の PowerPC ベースのアーキテクチャでは非常に高価です。
注意
コントロール ワードを変更する場合は、 _controlfp_s を使用し、x64 プラットフォームの場合、コントロール ワードを介して浮動小数点の精度を変更できないことに注意してください。
異なる丸めルールやその他の動作 (ソフトウェア頂点シェーダーやコンパイルの処理など) が必要なライブラリでは、コントロール ワードを保存して復元します。 ゲームで標準以外の丸めまたは FPU 例外を使用する必要がある場合は、浮動小数点制御ワードを保存して復元する必要があります。また、システム API を含め、これらの問題から安全であることが証明されていない外部コードが呼び出されないことを確認する必要があります。
DirectX ランタイムのオプションのインストール
DirectX をインストールするかどうかをユーザーに確認するゲームが多数存在します。 これにより、システムに最新の DirectX 再頒布可能パッケージがインストールされていると想定し、インストールをスキップした後、インストールが正常に続行されると、問題が発生する可能性があります。 ゲームに特定のバージョンの D3DX が必要な場合、またはインストールされていないその他の更新された機能が必要な場合、ゲームは機能せず、ユーザーは非常に不満を感じるでしょう。
ゲームのインストーラーは、ゲームがビルドされた DirectX 再頒布可能パッケージをサイレント インストールすることを強くお勧めします。 DirectX のインストール プロセスは、何かを更新する必要があるかどうかを確認し、更新しない場合はすばやく返すように設計されています。 そのため、DirectX のインストールについてユーザーに質問する必要はありません。
DirectX のサイレント インストールは、インストール パッケージから次のコマンドを実行することによって実行できます: dxsetup.exe /silent
さらに、再頒布可能フォルダーの実際のサイズは、ゲームのターゲット プラットフォームと使用に実際に必要なキャビネット ファイル (.cab) のみを含むように構成できます。
注意
dxsetup を使用する前に、「Not So Direct Setup」を参照してください。
スレッド同期の過剰な使用
ゲームをプロファイリングする場合、重要なセクションへの入退出に関連する人気スポットが見つかることがよくあります。 マルチコア CPU の普及に伴い、ゲームでのマルチスレッドの使用は大幅に増加し、多くの実装ではスレッド同期の多くの使用に依存しています。 競合がなくても重要なセクションを取る CPU 時間は非常に重要であり、他のすべての形式のスレッド同期はさらにコストがかかります。 そのため、これらのプリミティブの使用を最小限に抑えるために注意する必要があります。
ゲームの過剰な同期の一般的な原因は、 D3DCREATE_MULTITHREADEDの使用です。 このフラグは、複数のスレッドからのレンダリングに対して Direct3D スレッド セーフを実現する一方で、非常に保守的なアプローチを採用しているため、同期のオーバーヘッドが高くなります。 ゲームでは、このフラグを回避する必要があります。 代わりに、Direct3D との通信がすべて 1 つのスレッドから行われ、スレッド間の通信が直接処理されるように、エンジンを設計します。 マルチスレッド ゲームの設計の詳細については、「 Xbox 360 と Microsoft Windows での複数コアのコーディング」を参照してください。
RDTSC の使用
x86 命令 RDTSC の使用は推奨されません。 RDTSC は、CPU 周波数を動的に変更する一部の電源管理スキームと、サイクル カウンターがコア間で同期されない多くのマルチコア CPU で、タイミングを正しく計算できません。 代わりに、ゲームでは QueryPerformanceCounter API を使用する 必要があります。 RDTSC に関する問題と QueryPerformanceCounter での高解像度のタイミングの実装の詳細については、記事「Game Timing and Multicore Processors」を参照してください。