PC版で起動時に毎回シェーダーコンパイル処理が発生する原因

PC版のゲームで起動時にFShaderPipelineCache::NumPrecompilesRemaining()が0になるまで待つ(シェーダーコンパイル待ち)処理を入れています。

アプリケーションの初回起動時やドライバー更新時にこのシェーダーコンパイルが待ちが発生するのはわかるのですが、PCまたはグラボの固有の問題かもしれませんが、ゲーム起動時に2回目以降に初回より短い時間ですが毎回シェーダーコンパイル待ちが発生するケースが発生しています。

-clearPSODriverCacheを指定した場合に正常にキャッシュが削除されない不具合は、修正パッチを当てて問題解消済みです。

<br/>

原因として考えられるものを教えて下さい。

また、仕組み上、毎回少しはシェーダコンパイル待ちが発生することがあるものという場合はそれも知りたいです。

いまのところ、初回やドライバー更新時のみシェーダコンパイル待ちが発生するのを前提にシェーダコンパイル待ち時の説明を画面に表示しているので、その場合は、別途対処を考えたいと思っています。

<br/>

<br/>

<br/>

<br/>

<br/>

<br/>

----

再現手順

1.起動時に起動オプション-clearPSODriverCache を指定してシェーダーキャッシュをクリアした状態でゲーム開始、シェーダコンパイル待ちが終了した後、ゲームを終了させる。この時のシェーダーコンパイル待ちは数分

2.起動時に起動オプション-clearPSODriverCache はつけずにゲームを開始します。シェーダコンパイル待ちが数秒発生するPC(複数台)があります。

<br/>

<br/>

<br/>

<br/>

<br/>

<br/>

<br/>

<br/>

<br/>

<br/>

<br/>

<br/>

<br/>

お世話になっております。​

弊社で確認した際には該当しうる事象は確認できませんでした。共有可能な形で再現する最小のプロジェクトをご共有頂くことは可能でしょうか?

お手数をおかけしますがご確認の方よろしくお願い申し上げます。

すみません、すぐには最小プロジェクトを用意することができないのですが、問題はAMDのグラボでのみ発生しています。

シェーダーキャッシュが壊れているのかもしれないので、以下ページを参考にシェーダキャッシュをクリアしたのですが問題は解消しませんでした。

DirectX 12での『フォートナイト』がひどくカクつき、期待されるパフォーマンスを下回る - Fortnite Battle Royaleのサポート

この問題に関して何か情報おもちならば、教えて下さい。

お世話になっております。ご返答までにお時間を要しておりまして申し訳ございません。

1.問題

本件の"AMD GPU環境でのみ2回目以降の起動でもPSOプリコンパイル待ちが発生する" という現象について、エンジン側およびドライバ側におけるキャッシュ構造と挙動の違いが関係している可能性があります。UEのPSO管理はエンジン側のディスクキャッシュ (*.upipelinecache/*.spc) とGPUドライバ側のシェーダー/PSO キャッシュによる二層構造になっています。FShaderPipelineCache::NumPrecompilesRemaining()はエンジン側に登録されているプリコンパイル対象 PSO の残数を示す値であり、ドライバ側キャッシュのヒット可否までは直接反映されません。そのためエンジン側ではPSO作成済みと判断されていても、AMDドライバ側ではキャッシュミスと判定され、内部で再コンパイルが行われる可能性があります。

また、PSOキャッシュはプレイ内容に応じて継続的に増加する仕組みになっています。実行中に新しく使用されたPSOは *.rec.upipelinecacheファイルとして記録され、次回起動時にプリコンパイル対象へ追加されます。そのためプレイ内容や描画パスが完全に固定されていない環境では、2回目以降の起動であっても毎回少量のPSOプリコンパイルが発生する可能性があります。さらに、本問題が主にAMD GPU環境で観測されている点から、AMDドライバ側のキャッシュ管理やシェーダ最適化処理の特性も影響していると考えられます。たとえば、ドライバ内部キャッシュの部分的な無効化、キャッシュの再検証動作、ドライババージョン、Radeon側でのShader Cache設定状態などが関係している可能性があります。

これらの要素を総合すると本現象は、PSOキャッシュの二層構造、PSOキャッシュの継続的蓄積、AMDドライバ固有のキャッシュ挙動が組み合わさった結果として発生している可能性があると考えられます。

2.対策

AMD GPU環境に依存するわけではありませんが、UE5.4-5.7までに修正されたPSOに関連する修正としては以下のものがあります。これらの内容は改善の余地があるかもしれません。現状以下の修正確認においてはAMD GPU環境では再コンパイル等の問題が発生しないことが確認されております(確認したGPU種別やドライババージョンによっては、この問題が直接解消されるということを保証するものではありません)。

CL#35174606 : https://github.com/EpicGames/UnrealEngine/commit/17e411509c0e9136133f09b9b6478155f81e2cc6

CL#38718740 : https://github.com/EpicGames/UnrealEngine/commit/d9b62721d4544951f502ab5abf988985cd0a1e27

CL#40137406 : https://github.com/EpicGames/UnrealEngine/commit/29d56cd977569a54931ccd4de03c91e277b17612

また、本現象については、UEおよびGPUドライバの特性上、2回目以降の起動であっても一定量のPSOプリコンパイルが発生する可能性を完全に排除するのは難しいと考えられます。そのため「ゼロ待ち」とするよりも「一定のPSOコンパイルが発生を許容する」前提での設計に変更する方向が現実的であると考えられます。たとえばシェーダーコンパイルの待ちに対して「初回起動時、ドライバー更新後、またはキャッシュが無効化された場合に発生する可能性があります」といった内容に変更することで、シェーダーコンパイルの待ちに対する一般的な待ちである旨をユーザーに通知し、この待ちに対するプレイ体験の低下を緩和できるかと思われます。また、短時間(数秒程度)の待機ではメッセージを表示せず、一定時間以上継続した場合のみ表示する方式にすることで、AMD環境における短時間の待機によるユーザー体験への影響を軽減できる可能性があります。

技術的な観点では、NumPrecompilesRemaining == 0を厳密な進行条件とするのではなく、一定時間経過や完了率に応じて次の処理に進める方式を併用することが有効と考えられます。またAMD GPUを検出した場合のみ短時間のプリコンパイル待ちを緩和するオプションを設けることも検討の余地があります。さらに、FShaderPipelineCache::SavePipelineFileCache の呼び出しタイミングを見直し、PSO キャッシュが確実に保存されるようにすることで、起動ごとの再プリコンパイル発生頻度を低減できる可能性があります。

3.追加検証にあたって

本問題の原因をより正確に切り分けるためには、エンジン側およびドライバ側双方の挙動を確認すると良いかもしれません。起動時のログ出力を拡張しFShaderPipelineCache の開始ログおよび終了ログ、NumPrecompilesRemaining の時間推移、実際にプリコンパイルされた PSO 数などを出力することで、起動ごとの変化や GPU ごとの差異を把握できるようになります。次に、Saved 配下に生成される *.upipelinecache および *.rec.upipelinecache ファイルの差分を起動ごとに確認することで、PSO が実際にどの程度追加され続けているか、あるいは同一内容であるにもかかわらず再コンパイルが発生しているかといった傾向を調査することができます。

AMD環境ではRadeon SoftwareのShader Cache設定の有効・無効切り替えによる挙動の変化、ドライババージョン変更による再現性の違い、DxCache / DxcCache フォルダの監視なども有効な調査方法になります。さらに新規PSOの記録を無効化した検証用ビルドを用意し、その状態でも 2回目以降のコンパイル待ちが発生するかを確認することでUE側のPSOキャッシュ追加要因とドライバ側要因のどちらが主原因であるかを切り分けやすくなります。

状況が把握できました。

起動時の2回目以降のシェーダコンパイル待ちは、短いため、起こる前提で対応しようと思います。

ありがとうございます。