結論と対象読者

WebGLコンテキストは、GPUやドライバ、メモリ、ブラウザ判断などにより実行中に失われる場合があります。DotLCD Cameraでは、コンテキスト消失時に描画を止め、状態を保持し、復旧後にGPU資源を作り直すか、Canvas 2Dへ切り替える設計が必要です。

この記事は、WebGL2を主描画経路にする実装者と、長時間利用やスマートフォンで黒画面になる問題へ備えたい人向けです。

30秒要約

  • webglcontextlostは描画バッファが失われたときに発生します。
  • テクスチャ、シェーダー、バッファなどのGPU資源は作り直す前提で管理します。
  • JavaScript側のプリセットや入力状態はGPU資源と分離して保持します。
  • 復旧中は描画ループを止め、利用者へ状態を表示します。
  • 復旧できない場合はCanvas 2Dフォールバックを使います。

概要と背景

WebGLでは、画像、シェーダー、頂点バッファ、フレームバッファなどをGPU側へ作成します。これらは通常のJavaScriptオブジェクトと同じ寿命で永続するとは限りません。

コンテキストが失われると、WebGLの描画結果やGPU資源は利用できなくなります。その状態で通常どおり描画を続けると、黒画面、例外の連続、無駄な処理が発生する可能性があります。

DotLCDでは、論理解像度、4階調閾値、パレット、ディザー設定、残像係数、シードなどをGPU外の状態として保持します。これにより、復旧時に同じ設定から資源を再構築できます。

特徴・できること

消失を検知できる

Canvasへwebglcontextlostイベントを登録し、描画停止と復旧待ちへ移行できます。このイベントは通常の親要素へバブリングしないため、対象Canvasへ直接登録します。

復旧時に再初期化できる

webglcontextrestored後は、シェーダー、プログラム、テクスチャ、バッファ、Uniform設定などを再作成します。失われる前のWebGLオブジェクトをそのまま再利用しません。

Canvas 2Dへ切り替えられる

復旧が繰り返し失敗する場合や、端末負荷が高い場合は、同じ論理設定をCanvas 2D経路へ渡します。

現在の位置付けと利用上の前提

webglcontextlostwebglcontextrestoredはWebGLの標準イベントです。ただし、復旧が必ず成功するとは限りません。

実装では、次の状態を分けます。

  • 通常描画中
  • コンテキスト消失
  • 復旧処理中
  • 復旧成功
  • Canvas 2Dへ切替
  • 描画停止

WEBGL_lose_context拡張を利用できる環境では、開発時に意図的な消失と復旧を試験できます。これはテスト用であり、本番で消失を起こすための機能ではありません。

近い対象との比較

対象対応
一時的なフレーム低下品質やFPSを下げる
WebGLコンテキスト消失GPU資源を破棄扱いにして再構築
カメラ停止MediaStreamTrackを停止
ページ非表示描画ループを一時停止
復旧不能Canvas 2Dへ切替または停止

確認/試行の条件と注意点

  1. WEBGL_lose_contextで意図的にコンテキストを失わせます。
  2. 消失時に描画ループが止まるか確認します。
  3. UI操作やプリセット値が失われないか確認します。
  4. 復旧後にシェーダーとテクスチャが再作成されるか確認します。
  5. 残像バッファを復元するか、初期化するかを決めます。
  6. 復旧失敗時にCanvas 2Dへ切り替わるか確認します。
  7. 消失と復旧を複数回繰り返し、イベントリスナーやGPU資源が増殖しないか確認します。

復旧中に古いWebGLオブジェクトへアクセスし続けないことが重要です。アプリ状態とGPU状態を分離しておくと、フォールバックにも再現性にも有利です。

参考リンク

  • MDN: webglcontextlost event
  • https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/webglcontextlost_event
  • MDN: webglcontextrestored event
  • https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/webglcontextrestored_event
  • MDN: WEBGL_lose_context
  • https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_lose_context