プロンプトとユースケース
ブラウザのグラフィックスアプリが、バックグラウンドからの復帰、ドライバーの更新、またはリソースの逼迫の後に黒いキャンバスを表示します。WebGPUのデバイスロスト処理を設計してください:GPUDevice.lostの監視方法、意図的な破棄と一時的なロストの識別、デバイスおよびすべてのGPUリソースの再構築、並行するリカバリフロー同士の上書き防止について説明してください。また、未サポートのブラウザ、恒久的に利用できないアダプター、適切なレンダリングフォールバックについてもカバーしてください。
面接官が見ているポイント
lostを通常のレンダリングエラーではなく、デバイスライフサイクルのPromiseとして理解しているか。destroyedと、ブラウザ、ドライバー、またはリソース管理に起因するロストを区別できているか。- アダプター、デバイス、パイプライン、バッファ、テクスチャ、バインドグループの再構築。
- シングルフライトリカバリ、古いフレームのキャンセル、冪等な初期化の設計。
- セキュアコンテキスト、Worker、互換性、可観測性の処理。
最初に明確にすべき質問
- アプリはリアルタイムキャンバス、エディター、オフラインコンピュートジョブのどれであり、許容されるリカバリ時間はどれくらいか?
- CPU側のシーン、ユーザー入力、コミットされていない編集内容は維持される必要があるか?
- どのブラウザ、Worker、電源状態、メモリバジェットが対象範囲内か?
- 失敗時にはWebGL、静的プレビュー、またはリロードを促すプロンプトのいずれに切り替えるべきか?
30秒の回答
GPUデバイスを交換可能なセッションとして扱います。CPU側のシーンとリソース定義が正(オーソリティ)であり、GPUオブジェクトはキャッシュに過ぎません。device.lostを監視した後、シングルフライトの状態マシンが送信を一時停止し、GPUDeviceLostInfo.reasonを読み取ります。意図的なdestroyedの場合はセッションを終了し、それ以外の理由の場合は新しいアダプターとデバイスの取得、リソースの再構築、レンダーサイクルのリカバリをトリガーします。失敗が繰り返される場合や、すでにロストしたデバイスを返すアダプターの場合はフォールバックパスに入り、理由、リカバリ時間、失敗したリソースを記録します。
詳細なステップバイステップ解説
1. デバイスとアプリケーションの状態を分離する
シーングラフ、マテリアルパラメータ、ジオメトリデータ、テクスチャソースはCPU側に保持します。デバイス、キュー、バッファ、テクスチャ、パイプライン、バインドグループは使い捨てのGPUセッションオブジェクトであり、ビジネス上の真実ではありません。
2. ライフサイクルのPromiseを監視する
GPUDevice.lostはデバイスの生存期間中は保留(pending)状態を維持し、ロスト後にGPUDeviceLostInfoで解決されます。初期化後にリスナーを1つ登録し、そのコールバックを単一のリカバリ状態マシンに送ります。
3. ロスト理由を説明する
明示的なGPUDevice.destroy()は通常reason destroyedに対応するため、無条件の再起動をトリガーすべきではありません。ブラウザのリソース管理、ドライバーの更新、一時的なデバイス障害はリカバリできる可能性があります。取り外された、あるいは電源が無効化されたアダプターは、すでにロストしたデバイスを返し続ける可能性があります。
4. シングルフライトのリカバリゲートを使用する
すべてのアニメーションフレームで初期化を実行させるのではなく、リカバリのエントリポイントから同じPromiseを返します。送信を一時停止し、古いコマンドエンコーダーを破棄し、世代トークンを使用して古いデバイスからの非同期コールバックを拒否します。
5. 定義情報からリソースを再構築する
バッファの使用用途、テクスチャサイズとフォーマット、サンプラー、バインドグループレイアウト、シェーダーソース、パイプライン設定を永続化しておきます。新しいデバイスを作成した後、依存関係の順序で再構築します:シェーダーとレイアウト、パイプライン、バッファとテクスチャ、ビュー、バインドグループ、そしてキャンバスコンテキストとレンダーサイクルです。
6. CPUデータとバジェットを管理する
大きなテクスチャやジオメトリは、再読み込み可能なURL、IndexedDB、または圧縮キャッシュから取得できます。リカバリによってリソースの逼迫がすぐに再発しないよう、メモリバジェットとキャンセルシグナルを備えた、可視性と優先度を考慮したバッチでアップロードします。
7. 並行性と可視性を処理する
ページの非表示、Workerメッセージ、ユーザーによる再試行はいずれもリカバリを要求する可能性があります。状態マシンをready、lost、recovering、degradedに制限します。現在の世代のみがフレームを送信できます。ページが非表示の間は、コストの高い再構築を遅延させます。
8. フォールバックと可観測性を設計する
アダプターとデバイスをリクエストする前に、セキュアコンテキストとnavigator.gpuを確認します。失敗の繰り返し、恒久的なデバイスロスト、または未サポートのブラウザの後には、WebGL、静的プレビュー、または明確なリロードプロンプトに切り替えます。内部エラーをユーザーに公開することなく、理由、アダプター情報、試行回数、所要時間、失敗したリソース、フォールバック率を記録します。
トレードオフと境界
新しいデバイスをリクエストしても、古いバッファ、テクスチャ、パイプラインは復元されません。これらはCPU側の定義から再構築する必要があります。リカバリはすべてのロストが一時的であると仮定することはできず、無限の再試行ではなくバックオフを使用する必要があります。WebGPUはセキュアコンテキストを必要とし、依然として限定的な可用性(limited availability)にとどまります。WorkerもAPIを使用できますが、ブラウザとドライバーの違いはリリースマトリックスで管理すべき事項です。
ロールアウト計画と検証
- 作成手順が再現可能なCPUリソースマニフェストとGPUリソースファクトリを構築する。
- デバイス、アダプター、キャンバスコンテキスト、レンダーサイクルに世代管理とシングルフライトのリカバリ状態を追加する。
- 意図的な破棄、バックグラウンドからの復帰、ドライバーのリセット、メモリ逼迫、すでにロストしたアダプターのケースを注入してテストする。
- リソースの順序、ユーザー編集の維持、フレームの一時停止、フォールバックUI(Workerを含む)を検証する。
- MDNの
lostPromise、GPUDeviceLostInfo、セキュアコンテキスト、限定的な可用性に関する注記を互換性の根拠として使用する。
よくある間違いとフォローアップ
間違い1: requestDeviceを再度呼び出すだけにする
新しいデバイスには古いリソースが存在しません。パイプライン、バッファ、テクスチャ、ビュー、バインドグループをCPUの定義から再構築してください。
間違い2: すべての理由に対して自動的に再試行する
意図的な破棄は通常のシャットダウンである可能性があります。恒久的に利用できないアダプターに対して再試行を繰り返すと無限ループが発生します。バックオフを伴いながら理由に応じて分岐してください。
間違い3: アニメーションフレームごとにリカバリを開始する
並行するフローが共有状態に対して競合します。シングルフライトのPromiseと世代ゲートにより、現在の単一セッションのみが保証されます。
間違い4: GPUオブジェクトをビジネス状態として扱う
デバイスのロストによりGPUセッションはクリアされます。シーン、ユーザー入力、リソースソースはデバイスから独立させて維持してください。
間違い5: 未サポートおよびフォールバックパスを無視する
WebGPUはBaselineではなく、セキュアコンテキストでのみ利用可能です。早期に検出し、WebGL、静的プレビュー、またはリロードプランを提供してください。