Share via


Windows タイトルの主な問題

XNA デベロッパー コネクション (XDC)、ソフトウェア デザイン エンジニア

ゲーム ディベロッパー グループ

2006 年 12 月

Microsoft Windows Gaming and Graphics Technologies Developer Relations group は、毎年多くの Windows ゲームのパフォーマンスの分析を実行しています。これらのセッションでは、実践的な分析を行って、開発者からのフィードバックと毎日送られてくる質問に取り組んでいます。タイトルで生じる不可解なクラッシュやその他の問題を徹底的に追求することもあり、これによって開発者が直面している問題をより深く洞察することができます。

ここでは、現世代の PC ゲームで見られる一般的な問題の多くについて説明します。

  • CPU による制約を受けるパフォーマンス
  • 不適切なバッチ管理
  • 過度のメモリー コピー
  • 動的描画関数呼出しの過剰使用
  • ファイル処理時の高いオーバーヘッド
  • 遅く、ストレスのたまるインストール
  • 物理メモリーに関する考慮の欠如
  • リアルタイムのオーディオ サンプリング レート変換への過度の依存
  • 仮想メモリーの断片化
  • 浮動小数点制御ワードの操作
  • DirectX ランタイムの省略可能インストール
  • スレッド同期化の過剰使用
  • RDTSC の使用

CPU による制約を受けるパフォーマンス

大多数のゲームは、高パフォーマンスのグラフィックス プロセッシング ユニット (GPU) を搭載したシステムで CPU パフォーマンスによる制約を受けます。これは、描画関数呼出しの使用するバッチ処理が適切でないことが原因の場合もありますが、使用可能な CPU サイクルの大部分を他のゲーム システムが消費していることが原因となっている場合の方がより一般的です。まれに、非常に高いフィル レートまたはピクセル シェーダー要件、高分解能の設定、またはビデオ カードによる頂点シェーダーの低いパフォーマンスが原因となり GPU の制約を受ける場合があります。

ほとんどのタイトルが CPU による制約を受けるため、パフォーマンス向上に最も有効な方法は CPU 負荷の大きなゲーム システムを最適化することです。一般に、AI システムや物理システムおよび衝突検出関連のロジックが、正常に動作する Microsoft Direct3D アプリケーションにおいて CPU サイクルを消費する主なシステムです。これらのシステムを改善するためのあらゆる処理によって、ゲームの全体的なパフォーマンスが向上します。

不適切なバッチ管理

GPU との適切な並行処理を実現するには、コマンド バッファーがフラッディングするほどの多くのバッチは使用せずに、ビデオ カードを無駄なく稼動させておくのに十分なジオメトリが描画バッチに必要で、シェーダーの複雑性も適切である必要があります。現世代のハードウェアでは、ドライバーでのコマンド バッファー処理がパフォーマンスのボトルネックにならないように、フレームごとのバッチの描画関数呼出しを約 300 以下 (低パフォーマンスの CPU ではもっと少なく) にすることをお勧めします。その他の API ステート呼び出しとドライバーの組み合わせが、CPU 処理の大きな負荷になる場合があるため (シェーダーのドライバー コンパイル処理など)、PIX などのツールを使用して、定期的にパフォーマンスを分析することを強くお勧めします。

過度のメモリー コピー

ほとんどの PC タイトルでは、開発時にコンテンツ管理に都合の良いデータ構造と文字列を使用します。文字列比較、コピー、およびその他の処理に必要な CPU 処理のオーバーヘッドは大きくなることがあり、特に、キャッシュとメモリーのサブシステムに関連するパフォーマンス低下を考慮する場合には無視できなくなります。これらのシステムの開発時には、製品が最初のテストおよびリリース段階に入ったら文字列処理への依存をなくすか最小限に抑えるように計画する必要があります。

動的描画関数呼出しの過剰使用

最新のビデオ ハードウェアは、静的データの処理時には正常に機能します。通常、ハイエンド アダプターには大量のビデオ メモリーがありますが、このメモリーを動的データで効果的に利用することはできません。

動的頂点バッファーまたはインデックス バッファーの適度に効率的な利用パターンを動的コンテンツに実装することはできますが、多くのタイトルは、これを静的コンテンツで過剰使用しています。これは、バイナリ空間パーティショニング (BSP) ツリーによく見られます。また、データ構造がハードウェアにマップされておらず、フレームごとにバッファーで処理するデータ構造にジオメトリを格納した、ポータルベースのシステムの場合によく見られます。できる限り多くのコンテンツを静的リソースに配置することによって、ビデオ カードへのデータ転送の帯域幅のオーバーヘッドを削減することができ、オンボード VRAM を効率よく活用できるようになります。これにより対象のコンテンツの処理に関係する CPU およびキャッシュのオーバーヘッドを削減することができます。

ファイル処理時の高いオーバーヘッド

PC ゲームは、読み込みにかかる時間が長いと言われており、特に、読み込み時間に関して厳密な要件がある Xbox 用タイトルと比べると明らかです。多くのタイトルで行われているファイルのサブシステムの利用方法を分析することによって、いくつかの一般的な問題が明らかになっています。

ファイルを開くときのオーバーヘッドは通常、開発者が予期するものよりも大きくなります。オンデマンドのウイルス検出プログラムが広範囲で使用され、さらに NTFS の追加機能が使用されている状況では、ファイルを開く処理はかなり負担が大きくなります。一度に多くのファイルを開いたり、同じファイルを何度も開いたり閉じたりすることは、ファイル管理としては適切ではありません。一部のゲームでは、ファイルを開く前にファイルの存在をテストすることによって、このパフォーマンス コストの削減を試みています。NTFS でファイルの存在をテストするにはファイルを開く必要があるため、実際には、開く前にテストすることによってパフォーマンス コストが 2 倍かかることになります。

アドオン変更を許可するゲーム、また、データ ファイルのオーバーライドを確認するための開発用コードが残されているゲームでは、これらのファイルが存在しない場合でもファイルのチェックが実行されるため、ゲームの読み込みにかなりの時間がかかる場合があります。ゲームでは、特別なコマンドライン スイッチ、またはその他のモード インジケーターを使用して実行されるときにのみ、これらのファイルをチェックすることをお勧めします。これによって、この機能を利用するユーザーのみに実際にこれらの (通常は広範囲の) チェックにかかるパフォーマンス コストが適用されます。

さらに、次を行うことでファイル システムのパフォーマンスを向上できます。

  • ファイル システムに関する FILE_FLAG_RANDOM_ACCESS および FILE_FLAG_SEQUENTIAL_SCAN の適切な利用
  • バッファーのサイズ変更による OS の API の読み取り/書き込みに対する多数の呼び出しの回避
  • ファイルへの非同期的アクセス
  • バックグラウンドでのスレッドの読み込み

ゲームを最初に実行するときの変換に依存するのではなく、(ビルドまたはインストール時に) データをオフラインで変換することを強くお勧めします。最初の実行時の変換に依存すると、各ユーザーが大きなパフォーマンスの負荷を負うことになります。

遅く、ストレスのたまるインストール

別の一般的な問題は、多くの最新の PC ゲームでインストールが長時間になることです。インストーラーからユーザーに何度もプロンプトが表示されますが、"DirectX をインストールする必要はありません" など簡単なメッセージが表示されるだけの場合もあります。通常、このような不愉快なインストーラーでは、ゲームのインストールが実際に開始する前に [次へ] や [OK] を何度も選択させられます。インストールの開始後、タイトルによっては、ユーザーがゲームでプレイできるまでに 1 時間以上かかる場合があります。ゲーム プレイ体験の最初の 1 時間をインストールに当てたくはありません。

インストールの問題に対処するためにお勧めできる方法はたくさんあります。1 つ目は、ユーザーへの確認を単純にし、最小限にとどめます。2 つ目に、データファイルの一部またはすべてを、できるだけ配布先ディスクから直接使用できるようにゲーム データを設計します。最新の DVD ドライブの帯域幅は非常に大きいです。3 つ目に、タイトルにオンデマンド インストールを実装することを検討します。これにより、インストール処理を軽減または除去して、ユーザーが短時間でゲームを開始できるようになります(オンデマンド インストールの詳細については、「ゲームのオン デマンド インストール」を参照してください)。

ゲームのインストールに関するその他の推奨事項については、「ゲームのインストールの単純化」を参照してください。

物理メモリーに関する考慮の欠如

市場には多くの種類の PC ハードウェアがあるため、通常、タイトルではグラフィックの詳細レベルのデフォルト設定を選択するために、簡易的な構成テストを利用しています。タイトルによっては、これらのテストでビデオ メモリー サイズが決定されていますが、物理メモリー サイズとの関係が考慮されていない場合があります。デバイスが失われた状況に対処するために、ビデオ メモリーの大部分 (カード上のローカル VRAM とローカル以外の AGP メモリー アパーチュアの両方) を、管理リソースまたはカスタム データ構造を使用することによって、物理メモリーでバックアップする必要があります。ハイエンド ビデオ カードによっては、VRAM のサイズが、ローエンド CPU メモリーのサイズに匹敵するものがあります。ビデオ カードと比較して物理メモリーが制限されているシステムでは、ほとんどの場合 VRAM を効果的に使用することはできず、詳細度の低い設定を構成する必要があります。

リアルタイムのオーディオ サンプリング レート変換への過度の依存

他に、ハードウェア バッファーにミキシングするときに再生レートを変換するオーディオ システムでは、CPU サイクルが多く消費されます。Windows Driver Model (WDM) ドライバーを使用すると、ハードウェア バッファーのフォーマットは、アプリケーションによって直接制御されません。これは、カーネルレベルのリソースであるためで、代わりに、フォーマットはすべてのソースの最高品質のフォーマットとハードウェアの能力に基づいて選択されます。デフォルトでは、Windows XP はこの処理に高品質サンプリング レート変換を使用するため、オーディオ サンプリングのほとんどにレート変換が必要な場合は、CPU サイクルの多くの部分が消費されることになります。

すべての DirectSound バッファーを同一のサンプリング レートで作成することをお勧めします。Microsoft Win32 waveOut の何らかの機能を使用する場合は、これらの機能でも一貫したサンプリング レートを使用する必要があります。WDM ドライバーを使用する場合、バッファーはすべてカーネルによってミキシングされ、一部のバッファーに高いサンプリング レートを使用すると、その他すべてのバッファーのサンプリング レートは一致するように変換されます。これは、ストリーミング オーディオ圧縮解除バッファーを含め、すべてのオーディオ サンプリングに同じ再生レートが使用されるということを意味します。プライマリ バッファーのレートの設定は、Windows 98 または Windows Millennium Edition をターゲットとしていない限り、有効ではありません。

仮想メモリーの断片化

最近、32 ビットシステムにおけるプロセス メモリー空間の制限に関する問題が多く発生しています。ユーザーモード プロセスの 2 GB の仮想アドレス空間は、従来から十分すぎるぐらいですが、メモリーにマップされた大規模なファイルおよびカスタム メモリー アロケーターの使用の増加、および VRAM サイズ (プロセス空間にマップする必要がある) の増加により、仮想メモリー空間の割り当てに失敗する状況が発生するようになりました。Microsoft 以外の DLL の一部では、仮想アドレス空間の真ん中を固定の開始位置に使用しているものもありますが、これによって断片化が起こり、結果として割り当てに失敗しています。

この問題は、ゲームが、大規模な連続する仮想メモリー空間のチャンクを割り当てようとするカスタム メモリー割り当てスキームを使用するときに最も頻繁に発生します。アロケーターの記述では、仮想アドレス空間について必要に応じた妥当な容量を要求するようにしてください。たとえば、一度に 64 MB や 256 MB を要求しても、1 GB は要求しないでください。ただし、断片化が増えないように注意が必要です。64 ビットのオペレーティング システムとハードウェアの出現が、将来これらの問題の解決に役立つようになりますが、現世代の 32 ビットのシステムでは注意する必要があります。

浮動小数点制御ワードの操作

一部の開発者は、デバッグ用に、浮動小数点制御ワードを操作することによって、浮動小数点ユニット (FPU) で例外を使用可能にしています。これによって問題が発生することが多く、プロセスがクラッシュする可能性があります。呼び出し規則で ebx レジスタを保持する必要があるのと同様に、システムの大部分では、FPU がデフォルトの状態にあり、適切な結果を返すため、例外は生成しないことを仮定しています。ドライバーやその他のシステム コンポーネントでは、通常、不適切な状態の場合は標準のエラー値がレジスタに格納されるという前提の基に結果が計算されますが、例外が有効になっていると、例外は未処理となり、結果としてクラッシュが発生します。

Direct3D では、呼び出し側スレッドの初期化で浮動小数点ユニットが、単精度の四捨五入した値に設定されます。ただし、D3DCREATE_FPU_PRESERVE フラグが使用される状況では、浮動小数点制御ワードは使用されません。制御ワードはスレッドごとの設定であるため、アプリケーションのスレッドすべてを必ず単精度モードに設定することによって、パフォーマンスを最適化できる場合があります。_control_fp の呼び出しは、x64 ネイティブのコーディングでは無効です。x64 ネイティブのコーディングでは、代わりに SSE が排他的に使用され、これは、Xbox 360 CPU の PowerPC ベースのアーキテクチャでは極端に負荷が大きくなります。

さまざまな丸めルール、またはソフトウェア頂点シェーダーやコンパイルの処理などその他の動作が必要なライブラリでは、制御ワードを保存し、復元します。ゲームで非標準の丸めや FPU 例外を使用する必要がある場合は、浮動小数点制御ワードを保存し、復元する必要があります。また、システム API を含め、これらの問題に対する安全性が確認されていない外部コードをゲームで呼び出さないようにしてください。

DirectX ランタイムの省略可能インストール

多くのゲームで、ユーザーは DirectX をインストールするかどうか確認されます。ユーザーが、システムには最新の DirectX 再頒布可能ファイルがインストールされていると見なして、インストールを省略し、インストールが正常に続行されると、問題が生じる可能性があります。ゲームに特定のバージョンの D3DX またはインストールされていないその他の最新の機能が必要な場合は、ゲームは機能しなくなり、ユーザーは戸惑うことになります。

作成したゲームに対応する DirectX 再頒布可能ファイルが、ゲームのインストーラーによって自動的にインストールされるようにすることをお勧めします。DirectX のインストール プロセスを、更新が必要なものはないかどうか確認し、ない場合はすぐに制御を返すように設計します。これによって、ユーザーが DirectX のインストールを確認する必要がなくなります。

DirectX のサイレント インストールは、インストール パッケージの次のファイルでこのコマンドを実行することにより行うことができます。dxsetup.exe /silent

さらに、ゲームのターゲット プラットフォームおよび使用方法で、実際に必要なキャビネット ファイル (.cab) のみを含むように再頒布可能フォルダーの実際のサイズを構成できます。DirectX のインストールの詳細については、「DirectSetup での DirectX のインストール」を参照してください。

スレッド同期化の過剰使用

ゲームのプロファイリングのときに、主なホットスポットが重要なセクションの開始と終了に関係していることがわかる場合があります。マルチコア CPU の普及に伴い、ゲームでのマルチスレッドの使用が劇的に増加し、多くの実装がスレッドの同期化の頻繁な使用に依存しています。重要なセクションにかかる CPU 時間は競合がない場合でも非常に長く、その他すべてのスレッド同期化の形式ではより負担が大きくなります。このため、これらのプリミティブの使用を最小限に抑えるように注意する必要があります。

ゲームにおける過度の同期化の一般的な要因は、D3DCREATE_MULTITHREADED の使用です。このフラグは、複数のスレッドからのレンダリングで Direct3D をスレッド セーフにする一方で、保守的な方法を使用しているため、同期化のオーバーヘッドが高くなります。ゲームではこのフラグを使用しないでください。代わりに、Direct3D とのすべての通信が単一スレッドから実行され、スレッド間の通信はすべて直接処理されるようにエンジンを設計します。マルチスレッド ゲームの詳細については、記事「Xbox 360 および Microsoft Windows における複数コアのコーディング」を参照してください。

RDTSC の使用

x86 命令の RDTSC の使用はお勧めしません。RDTSC は、CPU 周波数を動的に変更する電源管理スキーム、およびサイクル カウンターがコア間で同期されていない多くのマルチコア CPU では、正常にタイミングを計算できません。ゲームでは代わりに QueryPerformanceCounter API を使用してください。RDTSC に関する問題および QueryPerformanceCounter を使用した高分解能タイミングの実装の詳細については、「ゲームのタイミングとマルチコア プロセッサ」を参照してください。